mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Ran the oh-mighty-pint
This commit is contained in:
+2
-2
@@ -1,7 +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;
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
|
||||
return [
|
||||
// Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php
|
||||
'aa' => __DIR__ . '/browsers/avant.png',
|
||||
'an' => __DIR__ . '/browsers/android-webview-beta.png',
|
||||
'ch' => __DIR__ . '/browsers/chrome.png',
|
||||
'ci' => __DIR__ . '/browsers/chrome.png', //Chrome Mobile iOS
|
||||
'cm' => __DIR__ . '/browsers/chrome.png', //Chrome Mobile
|
||||
'cr' => __DIR__ . '/browsers/chromium.png',
|
||||
'ff' => __DIR__ . '/browsers/firefox.png',
|
||||
'sf' => __DIR__ . '/browsers/safari.png',
|
||||
'mf' => __DIR__ . '/browsers/safari.png',
|
||||
'ps' => __DIR__ . '/browsers/edge.png',
|
||||
'oi' => __DIR__ . '/browsers/edge.png',
|
||||
'om' => __DIR__ . '/browsers/opera-mini.png',
|
||||
'op' => __DIR__ . '/browsers/opera.png',
|
||||
'on' => __DIR__ . '/browsers/opera.png',
|
||||
'aa' => __DIR__.'/browsers/avant.png',
|
||||
'an' => __DIR__.'/browsers/android-webview-beta.png',
|
||||
'ch' => __DIR__.'/browsers/chrome.png',
|
||||
'ci' => __DIR__.'/browsers/chrome.png', //Chrome Mobile iOS
|
||||
'cm' => __DIR__.'/browsers/chrome.png', //Chrome Mobile
|
||||
'cr' => __DIR__.'/browsers/chromium.png',
|
||||
'ff' => __DIR__.'/browsers/firefox.png',
|
||||
'sf' => __DIR__.'/browsers/safari.png',
|
||||
'mf' => __DIR__.'/browsers/safari.png',
|
||||
'ps' => __DIR__.'/browsers/edge.png',
|
||||
'oi' => __DIR__.'/browsers/edge.png',
|
||||
'om' => __DIR__.'/browsers/opera-mini.png',
|
||||
'op' => __DIR__.'/browsers/opera.png',
|
||||
'on' => __DIR__.'/browsers/opera.png',
|
||||
|
||||
/*
|
||||
'36' => '360 Phone Browser',
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'amex' => __DIR__ . '/credit-cards/amex.png',
|
||||
'argencard' => __DIR__ . '/credit-cards/argencard.png',
|
||||
'cabal' => __DIR__ . '/credit-cards/cabal.png',
|
||||
'censosud' => __DIR__ . '/credit-cards/consosud.png',
|
||||
'diners' => __DIR__ . '/credit-cards/diners.png',
|
||||
'discover' => __DIR__ . '/credit-cards/discover.png',
|
||||
'elo' => __DIR__ . '/credit-cards/elo.png',
|
||||
'hipercard' => __DIR__ . '/credit-cards/hipercard.png',
|
||||
'jcb' => __DIR__ . '/credit-cards/jcb.png',
|
||||
'mastercard' => __DIR__ . '/credit-cards/mastercard.png',
|
||||
'naranja' => __DIR__ . '/credit-cards/naranja.png',
|
||||
'targeta-shopping' => __DIR__ . '/credit-cards/tarjeta-shopping.png',
|
||||
'union-china-pay' => __DIR__ . '/credit-cards/union-china-pay.png',
|
||||
'visa' => __DIR__ . '/credit-cards/visa.png',
|
||||
'mir' => __DIR__ . '/credit-cards/mir.png',
|
||||
'maestro' => __DIR__ . '/credit-cards/maestro.png',
|
||||
'amex' => __DIR__.'/credit-cards/amex.png',
|
||||
'argencard' => __DIR__.'/credit-cards/argencard.png',
|
||||
'cabal' => __DIR__.'/credit-cards/cabal.png',
|
||||
'censosud' => __DIR__.'/credit-cards/consosud.png',
|
||||
'diners' => __DIR__.'/credit-cards/diners.png',
|
||||
'discover' => __DIR__.'/credit-cards/discover.png',
|
||||
'elo' => __DIR__.'/credit-cards/elo.png',
|
||||
'hipercard' => __DIR__.'/credit-cards/hipercard.png',
|
||||
'jcb' => __DIR__.'/credit-cards/jcb.png',
|
||||
'mastercard' => __DIR__.'/credit-cards/mastercard.png',
|
||||
'naranja' => __DIR__.'/credit-cards/naranja.png',
|
||||
'targeta-shopping' => __DIR__.'/credit-cards/tarjeta-shopping.png',
|
||||
'union-china-pay' => __DIR__.'/credit-cards/union-china-pay.png',
|
||||
'visa' => __DIR__.'/credit-cards/visa.png',
|
||||
'mir' => __DIR__.'/credit-cards/mir.png',
|
||||
'maestro' => __DIR__.'/credit-cards/maestro.png',
|
||||
];
|
||||
|
||||
+194
-194
@@ -1,198 +1,198 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'af' => __DIR__ . '/flags/af.png',
|
||||
'ao' => __DIR__ . '/flags/ao.png',
|
||||
'al' => __DIR__ . '/flags/al.png',
|
||||
'ad' => __DIR__ . '/flags/ad.png',
|
||||
'ae' => __DIR__ . '/flags/ae.png',
|
||||
'ar' => __DIR__ . '/flags/ar.png',
|
||||
'am' => __DIR__ . '/flags/am.png',
|
||||
'ag' => __DIR__ . '/flags/ag.png',
|
||||
'au' => __DIR__ . '/flags/au.png',
|
||||
'at' => __DIR__ . '/flags/at.png',
|
||||
'az' => __DIR__ . '/flags/az.png',
|
||||
'bi' => __DIR__ . '/flags/bi.png',
|
||||
'be' => __DIR__ . '/flags/be.png',
|
||||
'bj' => __DIR__ . '/flags/bj.png',
|
||||
'bf' => __DIR__ . '/flags/bf.png',
|
||||
'bd' => __DIR__ . '/flags/bd.png',
|
||||
'bg' => __DIR__ . '/flags/bg.png',
|
||||
'bh' => __DIR__ . '/flags/bh.png',
|
||||
'bs' => __DIR__ . '/flags/bs.png',
|
||||
'ba' => __DIR__ . '/flags/ba.png',
|
||||
'by' => __DIR__ . '/flags/by.png',
|
||||
'bz' => __DIR__ . '/flags/bz.png',
|
||||
'bo' => __DIR__ . '/flags/bo.png',
|
||||
'br' => __DIR__ . '/flags/br.png',
|
||||
'bb' => __DIR__ . '/flags/bb.png',
|
||||
'bn' => __DIR__ . '/flags/bn.png',
|
||||
'bt' => __DIR__ . '/flags/bt.png',
|
||||
'bw' => __DIR__ . '/flags/bw.png',
|
||||
'cf' => __DIR__ . '/flags/cf.png',
|
||||
'ca' => __DIR__ . '/flags/ca.png',
|
||||
'ch' => __DIR__ . '/flags/ch.png',
|
||||
'cl' => __DIR__ . '/flags/cl.png',
|
||||
'cn' => __DIR__ . '/flags/cn.png',
|
||||
'ci' => __DIR__ . '/flags/ci.png',
|
||||
'cm' => __DIR__ . '/flags/cm.png',
|
||||
'cd' => __DIR__ . '/flags/cd.png',
|
||||
'cg' => __DIR__ . '/flags/cg.png',
|
||||
'co' => __DIR__ . '/flags/co.png',
|
||||
'km' => __DIR__ . '/flags/km.png',
|
||||
'cv' => __DIR__ . '/flags/cv.png',
|
||||
'cr' => __DIR__ . '/flags/cr.png',
|
||||
'cu' => __DIR__ . '/flags/cu.png',
|
||||
'cy' => __DIR__ . '/flags/cy.png',
|
||||
'cz' => __DIR__ . '/flags/cz.png',
|
||||
'de' => __DIR__ . '/flags/de.png',
|
||||
'dj' => __DIR__ . '/flags/dj.png',
|
||||
'dm' => __DIR__ . '/flags/dm.png',
|
||||
'dk' => __DIR__ . '/flags/dk.png',
|
||||
'do' => __DIR__ . '/flags/do.png',
|
||||
'dz' => __DIR__ . '/flags/dz.png',
|
||||
'ec' => __DIR__ . '/flags/ec.png',
|
||||
'eg' => __DIR__ . '/flags/eg.png',
|
||||
'er' => __DIR__ . '/flags/er.png',
|
||||
'es' => __DIR__ . '/flags/es.png',
|
||||
'ee' => __DIR__ . '/flags/ee.png',
|
||||
'et' => __DIR__ . '/flags/et.png',
|
||||
'fi' => __DIR__ . '/flags/fi.png',
|
||||
'fj' => __DIR__ . '/flags/fj.png',
|
||||
'fr' => __DIR__ . '/flags/fr.png',
|
||||
'fm' => __DIR__ . '/flags/fm.png',
|
||||
'ga' => __DIR__ . '/flags/ga.png',
|
||||
'gb' => __DIR__ . '/flags/gb.png',
|
||||
'ge' => __DIR__ . '/flags/ge.png',
|
||||
'gh' => __DIR__ . '/flags/gh.png',
|
||||
'gn' => __DIR__ . '/flags/gn.png',
|
||||
'gm' => __DIR__ . '/flags/gm.png',
|
||||
'gw' => __DIR__ . '/flags/gw.png',
|
||||
'gq' => __DIR__ . '/flags/gq.png',
|
||||
'gr' => __DIR__ . '/flags/gr.png',
|
||||
'gd' => __DIR__ . '/flags/gd.png',
|
||||
'gt' => __DIR__ . '/flags/gt.png',
|
||||
'gy' => __DIR__ . '/flags/gy.png',
|
||||
'hn' => __DIR__ . '/flags/hn.png',
|
||||
'hr' => __DIR__ . '/flags/hr.png',
|
||||
'ht' => __DIR__ . '/flags/ht.png',
|
||||
'hu' => __DIR__ . '/flags/hu.png',
|
||||
'id' => __DIR__ . '/flags/id.png',
|
||||
'in' => __DIR__ . '/flags/in.png',
|
||||
'ie' => __DIR__ . '/flags/ie.png',
|
||||
'ir' => __DIR__ . '/flags/ir.png',
|
||||
'iq' => __DIR__ . '/flags/iq.png',
|
||||
'is' => __DIR__ . '/flags/is.png',
|
||||
'il' => __DIR__ . '/flags/il.png',
|
||||
'it' => __DIR__ . '/flags/it.png',
|
||||
'jm' => __DIR__ . '/flags/jm.png',
|
||||
'jo' => __DIR__ . '/flags/jo.png',
|
||||
'jp' => __DIR__ . '/flags/jp.png',
|
||||
'kz' => __DIR__ . '/flags/kz.png',
|
||||
'ke' => __DIR__ . '/flags/ke.png',
|
||||
'kg' => __DIR__ . '/flags/kg.png',
|
||||
'kh' => __DIR__ . '/flags/kh.png',
|
||||
'ki' => __DIR__ . '/flags/ki.png',
|
||||
'kn' => __DIR__ . '/flags/kn.png',
|
||||
'kr' => __DIR__ . '/flags/kr.png',
|
||||
'kw' => __DIR__ . '/flags/kw.png',
|
||||
'la' => __DIR__ . '/flags/la.png',
|
||||
'lb' => __DIR__ . '/flags/lb.png',
|
||||
'lr' => __DIR__ . '/flags/lr.png',
|
||||
'ly' => __DIR__ . '/flags/ly.png',
|
||||
'lc' => __DIR__ . '/flags/lc.png',
|
||||
'li' => __DIR__ . '/flags/li.png',
|
||||
'lk' => __DIR__ . '/flags/lk.png',
|
||||
'ls' => __DIR__ . '/flags/ls.png',
|
||||
'lt' => __DIR__ . '/flags/ls.png',
|
||||
'lu' => __DIR__ . '/flags/lu.png',
|
||||
'lv' => __DIR__ . '/flags/lv.png',
|
||||
'ma' => __DIR__ . '/flags/ma.png',
|
||||
'mc' => __DIR__ . '/flags/mc.png',
|
||||
'md' => __DIR__ . '/flags/md.png',
|
||||
'mg' => __DIR__ . '/flags/mg.png',
|
||||
'mv' => __DIR__ . '/flags/mv.png',
|
||||
'mx' => __DIR__ . '/flags/mx.png',
|
||||
'mh' => __DIR__ . '/flags/mh.png',
|
||||
'mk' => __DIR__ . '/flags/mk.png',
|
||||
'ml' => __DIR__ . '/flags/ml.png',
|
||||
'mt' => __DIR__ . '/flags/mt.png',
|
||||
'mm' => __DIR__ . '/flags/mm.png',
|
||||
'me' => __DIR__ . '/flags/me.png',
|
||||
'mn' => __DIR__ . '/flags/mn.png',
|
||||
'mz' => __DIR__ . '/flags/mz.png',
|
||||
'mr' => __DIR__ . '/flags/mr.png',
|
||||
'mu' => __DIR__ . '/flags/mu.png',
|
||||
'mw' => __DIR__ . '/flags/mw.png',
|
||||
'my' => __DIR__ . '/flags/my.png',
|
||||
'na' => __DIR__ . '/flags/na.png',
|
||||
'ne' => __DIR__ . '/flags/ne.png',
|
||||
'ng' => __DIR__ . '/flags/ng.png',
|
||||
'ni' => __DIR__ . '/flags/ni.png',
|
||||
'nl' => __DIR__ . '/flags/nl.png',
|
||||
'no' => __DIR__ . '/flags/no.png',
|
||||
'np' => __DIR__ . '/flags/np.png',
|
||||
'nr' => __DIR__ . '/flags/nr.png',
|
||||
'nz' => __DIR__ . '/flags/nz.png',
|
||||
'om' => __DIR__ . '/flags/om.png',
|
||||
'pk' => __DIR__ . '/flags/pk.png',
|
||||
'pa' => __DIR__ . '/flags/pa.png',
|
||||
'pe' => __DIR__ . '/flags/pe.png',
|
||||
'ph' => __DIR__ . '/flags/ph.png',
|
||||
'pw' => __DIR__ . '/flags/pw.png',
|
||||
'pg' => __DIR__ . '/flags/pg.png',
|
||||
'pl' => __DIR__ . '/flags/pl.png',
|
||||
'kp' => __DIR__ . '/flags/kp.png',
|
||||
'pt' => __DIR__ . '/flags/pt.png',
|
||||
'py' => __DIR__ . '/flags/py.png',
|
||||
'qa' => __DIR__ . '/flags/qa.png',
|
||||
'ro' => __DIR__ . '/flags/ro.png',
|
||||
'ru' => __DIR__ . '/flags/ru.png',
|
||||
'rw' => __DIR__ . '/flags/rw.png',
|
||||
'sa' => __DIR__ . '/flags/sa.png',
|
||||
'sd' => __DIR__ . '/flags/sd.png',
|
||||
'sn' => __DIR__ . '/flags/sn.png',
|
||||
'sg' => __DIR__ . '/flags/sg.png',
|
||||
'sb' => __DIR__ . '/flags/sb.png',
|
||||
'sl' => __DIR__ . '/flags/sl.png',
|
||||
'sv' => __DIR__ . '/flags/sv.png',
|
||||
'sm' => __DIR__ . '/flags/sm.png',
|
||||
'so' => __DIR__ . '/flags/so.png',
|
||||
'rs' => __DIR__ . '/flags/rs.png',
|
||||
'ss' => __DIR__ . '/flags/ss.png',
|
||||
'st' => __DIR__ . '/flags/st.png',
|
||||
'sr' => __DIR__ . '/flags/sr.png',
|
||||
'sk' => __DIR__ . '/flags/sk.png',
|
||||
'si' => __DIR__ . '/flags/si.png',
|
||||
'se' => __DIR__ . '/flags/se.png',
|
||||
'sz' => __DIR__ . '/flags/sz.png',
|
||||
'sc' => __DIR__ . '/flags/sc.png',
|
||||
'sy' => __DIR__ . '/flags/sy.png',
|
||||
'td' => __DIR__ . '/flags/td.png',
|
||||
'tg' => __DIR__ . '/flags/tg.png',
|
||||
'th' => __DIR__ . '/flags/th.png',
|
||||
'tj' => __DIR__ . '/flags/tj.png',
|
||||
'tm' => __DIR__ . '/flags/tm.png',
|
||||
'tl' => __DIR__ . '/flags/tl.png',
|
||||
'to' => __DIR__ . '/flags/to.png',
|
||||
'tt' => __DIR__ . '/flags/tt.png',
|
||||
'tn' => __DIR__ . '/flags/tn.png',
|
||||
'tr' => __DIR__ . '/flags/tr.png',
|
||||
'tv' => __DIR__ . '/flags/tv.png',
|
||||
'tz' => __DIR__ . '/flags/tz.png',
|
||||
'ug' => __DIR__ . '/flags/ug.png',
|
||||
'ua' => __DIR__ . '/flags/ua.png',
|
||||
'uy' => __DIR__ . '/flags/uy.png',
|
||||
'us' => __DIR__ . '/flags/us.png',
|
||||
'uz' => __DIR__ . '/flags/uz.png',
|
||||
'va' => __DIR__ . '/flags/va.png',
|
||||
'vc' => __DIR__ . '/flags/vc.png',
|
||||
've' => __DIR__ . '/flags/ve.png',
|
||||
'vn' => __DIR__ . '/flags/vn.png',
|
||||
'vu' => __DIR__ . '/flags/vu.png',
|
||||
'ws' => __DIR__ . '/flags/ws.png',
|
||||
'ye' => __DIR__ . '/flags/ye.png',
|
||||
'za' => __DIR__ . '/flags/za.png',
|
||||
'zm' => __DIR__ . '/flags/zm.png',
|
||||
'zw' => __DIR__ . '/flags/zw.png',
|
||||
'af' => __DIR__.'/flags/af.png',
|
||||
'ao' => __DIR__.'/flags/ao.png',
|
||||
'al' => __DIR__.'/flags/al.png',
|
||||
'ad' => __DIR__.'/flags/ad.png',
|
||||
'ae' => __DIR__.'/flags/ae.png',
|
||||
'ar' => __DIR__.'/flags/ar.png',
|
||||
'am' => __DIR__.'/flags/am.png',
|
||||
'ag' => __DIR__.'/flags/ag.png',
|
||||
'au' => __DIR__.'/flags/au.png',
|
||||
'at' => __DIR__.'/flags/at.png',
|
||||
'az' => __DIR__.'/flags/az.png',
|
||||
'bi' => __DIR__.'/flags/bi.png',
|
||||
'be' => __DIR__.'/flags/be.png',
|
||||
'bj' => __DIR__.'/flags/bj.png',
|
||||
'bf' => __DIR__.'/flags/bf.png',
|
||||
'bd' => __DIR__.'/flags/bd.png',
|
||||
'bg' => __DIR__.'/flags/bg.png',
|
||||
'bh' => __DIR__.'/flags/bh.png',
|
||||
'bs' => __DIR__.'/flags/bs.png',
|
||||
'ba' => __DIR__.'/flags/ba.png',
|
||||
'by' => __DIR__.'/flags/by.png',
|
||||
'bz' => __DIR__.'/flags/bz.png',
|
||||
'bo' => __DIR__.'/flags/bo.png',
|
||||
'br' => __DIR__.'/flags/br.png',
|
||||
'bb' => __DIR__.'/flags/bb.png',
|
||||
'bn' => __DIR__.'/flags/bn.png',
|
||||
'bt' => __DIR__.'/flags/bt.png',
|
||||
'bw' => __DIR__.'/flags/bw.png',
|
||||
'cf' => __DIR__.'/flags/cf.png',
|
||||
'ca' => __DIR__.'/flags/ca.png',
|
||||
'ch' => __DIR__.'/flags/ch.png',
|
||||
'cl' => __DIR__.'/flags/cl.png',
|
||||
'cn' => __DIR__.'/flags/cn.png',
|
||||
'ci' => __DIR__.'/flags/ci.png',
|
||||
'cm' => __DIR__.'/flags/cm.png',
|
||||
'cd' => __DIR__.'/flags/cd.png',
|
||||
'cg' => __DIR__.'/flags/cg.png',
|
||||
'co' => __DIR__.'/flags/co.png',
|
||||
'km' => __DIR__.'/flags/km.png',
|
||||
'cv' => __DIR__.'/flags/cv.png',
|
||||
'cr' => __DIR__.'/flags/cr.png',
|
||||
'cu' => __DIR__.'/flags/cu.png',
|
||||
'cy' => __DIR__.'/flags/cy.png',
|
||||
'cz' => __DIR__.'/flags/cz.png',
|
||||
'de' => __DIR__.'/flags/de.png',
|
||||
'dj' => __DIR__.'/flags/dj.png',
|
||||
'dm' => __DIR__.'/flags/dm.png',
|
||||
'dk' => __DIR__.'/flags/dk.png',
|
||||
'do' => __DIR__.'/flags/do.png',
|
||||
'dz' => __DIR__.'/flags/dz.png',
|
||||
'ec' => __DIR__.'/flags/ec.png',
|
||||
'eg' => __DIR__.'/flags/eg.png',
|
||||
'er' => __DIR__.'/flags/er.png',
|
||||
'es' => __DIR__.'/flags/es.png',
|
||||
'ee' => __DIR__.'/flags/ee.png',
|
||||
'et' => __DIR__.'/flags/et.png',
|
||||
'fi' => __DIR__.'/flags/fi.png',
|
||||
'fj' => __DIR__.'/flags/fj.png',
|
||||
'fr' => __DIR__.'/flags/fr.png',
|
||||
'fm' => __DIR__.'/flags/fm.png',
|
||||
'ga' => __DIR__.'/flags/ga.png',
|
||||
'gb' => __DIR__.'/flags/gb.png',
|
||||
'ge' => __DIR__.'/flags/ge.png',
|
||||
'gh' => __DIR__.'/flags/gh.png',
|
||||
'gn' => __DIR__.'/flags/gn.png',
|
||||
'gm' => __DIR__.'/flags/gm.png',
|
||||
'gw' => __DIR__.'/flags/gw.png',
|
||||
'gq' => __DIR__.'/flags/gq.png',
|
||||
'gr' => __DIR__.'/flags/gr.png',
|
||||
'gd' => __DIR__.'/flags/gd.png',
|
||||
'gt' => __DIR__.'/flags/gt.png',
|
||||
'gy' => __DIR__.'/flags/gy.png',
|
||||
'hn' => __DIR__.'/flags/hn.png',
|
||||
'hr' => __DIR__.'/flags/hr.png',
|
||||
'ht' => __DIR__.'/flags/ht.png',
|
||||
'hu' => __DIR__.'/flags/hu.png',
|
||||
'id' => __DIR__.'/flags/id.png',
|
||||
'in' => __DIR__.'/flags/in.png',
|
||||
'ie' => __DIR__.'/flags/ie.png',
|
||||
'ir' => __DIR__.'/flags/ir.png',
|
||||
'iq' => __DIR__.'/flags/iq.png',
|
||||
'is' => __DIR__.'/flags/is.png',
|
||||
'il' => __DIR__.'/flags/il.png',
|
||||
'it' => __DIR__.'/flags/it.png',
|
||||
'jm' => __DIR__.'/flags/jm.png',
|
||||
'jo' => __DIR__.'/flags/jo.png',
|
||||
'jp' => __DIR__.'/flags/jp.png',
|
||||
'kz' => __DIR__.'/flags/kz.png',
|
||||
'ke' => __DIR__.'/flags/ke.png',
|
||||
'kg' => __DIR__.'/flags/kg.png',
|
||||
'kh' => __DIR__.'/flags/kh.png',
|
||||
'ki' => __DIR__.'/flags/ki.png',
|
||||
'kn' => __DIR__.'/flags/kn.png',
|
||||
'kr' => __DIR__.'/flags/kr.png',
|
||||
'kw' => __DIR__.'/flags/kw.png',
|
||||
'la' => __DIR__.'/flags/la.png',
|
||||
'lb' => __DIR__.'/flags/lb.png',
|
||||
'lr' => __DIR__.'/flags/lr.png',
|
||||
'ly' => __DIR__.'/flags/ly.png',
|
||||
'lc' => __DIR__.'/flags/lc.png',
|
||||
'li' => __DIR__.'/flags/li.png',
|
||||
'lk' => __DIR__.'/flags/lk.png',
|
||||
'ls' => __DIR__.'/flags/ls.png',
|
||||
'lt' => __DIR__.'/flags/ls.png',
|
||||
'lu' => __DIR__.'/flags/lu.png',
|
||||
'lv' => __DIR__.'/flags/lv.png',
|
||||
'ma' => __DIR__.'/flags/ma.png',
|
||||
'mc' => __DIR__.'/flags/mc.png',
|
||||
'md' => __DIR__.'/flags/md.png',
|
||||
'mg' => __DIR__.'/flags/mg.png',
|
||||
'mv' => __DIR__.'/flags/mv.png',
|
||||
'mx' => __DIR__.'/flags/mx.png',
|
||||
'mh' => __DIR__.'/flags/mh.png',
|
||||
'mk' => __DIR__.'/flags/mk.png',
|
||||
'ml' => __DIR__.'/flags/ml.png',
|
||||
'mt' => __DIR__.'/flags/mt.png',
|
||||
'mm' => __DIR__.'/flags/mm.png',
|
||||
'me' => __DIR__.'/flags/me.png',
|
||||
'mn' => __DIR__.'/flags/mn.png',
|
||||
'mz' => __DIR__.'/flags/mz.png',
|
||||
'mr' => __DIR__.'/flags/mr.png',
|
||||
'mu' => __DIR__.'/flags/mu.png',
|
||||
'mw' => __DIR__.'/flags/mw.png',
|
||||
'my' => __DIR__.'/flags/my.png',
|
||||
'na' => __DIR__.'/flags/na.png',
|
||||
'ne' => __DIR__.'/flags/ne.png',
|
||||
'ng' => __DIR__.'/flags/ng.png',
|
||||
'ni' => __DIR__.'/flags/ni.png',
|
||||
'nl' => __DIR__.'/flags/nl.png',
|
||||
'no' => __DIR__.'/flags/no.png',
|
||||
'np' => __DIR__.'/flags/np.png',
|
||||
'nr' => __DIR__.'/flags/nr.png',
|
||||
'nz' => __DIR__.'/flags/nz.png',
|
||||
'om' => __DIR__.'/flags/om.png',
|
||||
'pk' => __DIR__.'/flags/pk.png',
|
||||
'pa' => __DIR__.'/flags/pa.png',
|
||||
'pe' => __DIR__.'/flags/pe.png',
|
||||
'ph' => __DIR__.'/flags/ph.png',
|
||||
'pw' => __DIR__.'/flags/pw.png',
|
||||
'pg' => __DIR__.'/flags/pg.png',
|
||||
'pl' => __DIR__.'/flags/pl.png',
|
||||
'kp' => __DIR__.'/flags/kp.png',
|
||||
'pt' => __DIR__.'/flags/pt.png',
|
||||
'py' => __DIR__.'/flags/py.png',
|
||||
'qa' => __DIR__.'/flags/qa.png',
|
||||
'ro' => __DIR__.'/flags/ro.png',
|
||||
'ru' => __DIR__.'/flags/ru.png',
|
||||
'rw' => __DIR__.'/flags/rw.png',
|
||||
'sa' => __DIR__.'/flags/sa.png',
|
||||
'sd' => __DIR__.'/flags/sd.png',
|
||||
'sn' => __DIR__.'/flags/sn.png',
|
||||
'sg' => __DIR__.'/flags/sg.png',
|
||||
'sb' => __DIR__.'/flags/sb.png',
|
||||
'sl' => __DIR__.'/flags/sl.png',
|
||||
'sv' => __DIR__.'/flags/sv.png',
|
||||
'sm' => __DIR__.'/flags/sm.png',
|
||||
'so' => __DIR__.'/flags/so.png',
|
||||
'rs' => __DIR__.'/flags/rs.png',
|
||||
'ss' => __DIR__.'/flags/ss.png',
|
||||
'st' => __DIR__.'/flags/st.png',
|
||||
'sr' => __DIR__.'/flags/sr.png',
|
||||
'sk' => __DIR__.'/flags/sk.png',
|
||||
'si' => __DIR__.'/flags/si.png',
|
||||
'se' => __DIR__.'/flags/se.png',
|
||||
'sz' => __DIR__.'/flags/sz.png',
|
||||
'sc' => __DIR__.'/flags/sc.png',
|
||||
'sy' => __DIR__.'/flags/sy.png',
|
||||
'td' => __DIR__.'/flags/td.png',
|
||||
'tg' => __DIR__.'/flags/tg.png',
|
||||
'th' => __DIR__.'/flags/th.png',
|
||||
'tj' => __DIR__.'/flags/tj.png',
|
||||
'tm' => __DIR__.'/flags/tm.png',
|
||||
'tl' => __DIR__.'/flags/tl.png',
|
||||
'to' => __DIR__.'/flags/to.png',
|
||||
'tt' => __DIR__.'/flags/tt.png',
|
||||
'tn' => __DIR__.'/flags/tn.png',
|
||||
'tr' => __DIR__.'/flags/tr.png',
|
||||
'tv' => __DIR__.'/flags/tv.png',
|
||||
'tz' => __DIR__.'/flags/tz.png',
|
||||
'ug' => __DIR__.'/flags/ug.png',
|
||||
'ua' => __DIR__.'/flags/ua.png',
|
||||
'uy' => __DIR__.'/flags/uy.png',
|
||||
'us' => __DIR__.'/flags/us.png',
|
||||
'uz' => __DIR__.'/flags/uz.png',
|
||||
'va' => __DIR__.'/flags/va.png',
|
||||
'vc' => __DIR__.'/flags/vc.png',
|
||||
've' => __DIR__.'/flags/ve.png',
|
||||
'vn' => __DIR__.'/flags/vn.png',
|
||||
'vu' => __DIR__.'/flags/vu.png',
|
||||
'ws' => __DIR__.'/flags/ws.png',
|
||||
'ye' => __DIR__.'/flags/ye.png',
|
||||
'za' => __DIR__.'/flags/za.png',
|
||||
'zm' => __DIR__.'/flags/zm.png',
|
||||
'zw' => __DIR__.'/flags/zw.png',
|
||||
];
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
return [
|
||||
// Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php
|
||||
'AND' => __DIR__ . '/os/android.png',
|
||||
'ATV' => __DIR__ . '/os/apple-tv.png',
|
||||
'COS' => __DIR__ . '/os/chrome-os.png',
|
||||
'AND' => __DIR__.'/os/android.png',
|
||||
'ATV' => __DIR__.'/os/apple-tv.png',
|
||||
'COS' => __DIR__.'/os/chrome-os.png',
|
||||
|
||||
/*
|
||||
'AIX' => 'AIX',
|
||||
|
||||
+24
-25
@@ -16,7 +16,6 @@ $auth = Config::getParam('auth', []);
|
||||
* attributes => list of attributes
|
||||
* indexes => list of indexes
|
||||
*/
|
||||
|
||||
$collections = [
|
||||
'databases' => [
|
||||
'$collection' => ID::custom(Database::METADATA),
|
||||
@@ -839,7 +838,7 @@ $collections = [
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -946,16 +945,16 @@ $collections = [
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('registered'),
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
'$id' => ID::custom('registered'),
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
||||
],
|
||||
'indexes' => [
|
||||
@@ -1193,7 +1192,7 @@ $collections = [
|
||||
'attributes' => ['projectInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -1388,7 +1387,7 @@ $collections = [
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -1453,7 +1452,7 @@ $collections = [
|
||||
'attributes' => ['search'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -1538,7 +1537,7 @@ $collections = [
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -2415,7 +2414,7 @@ $collections = [
|
||||
'default' => false,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -2595,7 +2594,7 @@ $collections = [
|
||||
'default' => '',
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -2604,7 +2603,7 @@ $collections = [
|
||||
'attributes' => ['deploymentId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -3010,7 +3009,7 @@ $collections = [
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
'stats' => [
|
||||
@@ -3147,7 +3146,7 @@ $collections = [
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [], //TODO: use json filter
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -3157,7 +3156,7 @@ $collections = [
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_DESC],
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
'cache' => [
|
||||
'$collection' => Database::METADATA,
|
||||
@@ -3197,7 +3196,7 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_accessedAt',
|
||||
@@ -3465,7 +3464,7 @@ $collections = [
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
'variables' => [
|
||||
@@ -3515,7 +3514,7 @@ $collections = [
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [ 'encrypt' ]
|
||||
'filters' => ['encrypt'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('search'),
|
||||
|
||||
@@ -239,7 +239,7 @@ return [
|
||||
Exception::AVATAR_SET_NOT_FOUND => [
|
||||
'name' => Exception::AVATAR_SET_NOT_FOUND,
|
||||
'description' => 'The requested avatar set could not be found.',
|
||||
'code' => 404
|
||||
'code' => 404,
|
||||
],
|
||||
Exception::AVATAR_NOT_FOUND => [
|
||||
'name' => Exception::AVATAR_NOT_FOUND,
|
||||
@@ -361,13 +361,13 @@ return [
|
||||
Exception::DATABASE_NOT_FOUND => [
|
||||
'name' => Exception::DATABASE_NOT_FOUND,
|
||||
'description' => 'Database not found',
|
||||
'code' => 404
|
||||
'code' => 404,
|
||||
],
|
||||
|
||||
Exception::DATABASE_ALREADY_EXISTS => [
|
||||
'name' => Exception::DATABASE_ALREADY_EXISTS,
|
||||
'description' => 'Database already exists',
|
||||
'code' => 409
|
||||
'code' => 409,
|
||||
],
|
||||
|
||||
/** Collections */
|
||||
|
||||
+31
-31
@@ -19,7 +19,7 @@ return [
|
||||
'$description' => 'This event triggers when a session for a user is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a session for a user is deleted.'
|
||||
'$description' => 'This event triggers when a session for a user is deleted.',
|
||||
],
|
||||
],
|
||||
'recovery' => [
|
||||
@@ -30,7 +30,7 @@ return [
|
||||
'$description' => 'This event triggers when a recovery token for a user is created.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a recovery token for a user is validated.'
|
||||
'$description' => 'This event triggers when a recovery token for a user is validated.',
|
||||
],
|
||||
],
|
||||
'verification' => [
|
||||
@@ -41,11 +41,11 @@ return [
|
||||
'$description' => 'This event triggers when a verification token for a user is created.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a verification token for a user is validated.'
|
||||
'$description' => 'This event triggers when a verification token for a user is validated.',
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a user is created.'
|
||||
'$description' => 'This event triggers when a user is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a user is deleted.',
|
||||
@@ -67,7 +67,7 @@ return [
|
||||
'prefs' => [
|
||||
'$description' => 'This event triggers when a user\'s preferences is updated.',
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
'databases' => [
|
||||
'$model' => Response::MODEL_DATABASE,
|
||||
@@ -85,10 +85,10 @@ return [
|
||||
'$description' => 'This event triggers when a document is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a document is deleted.'
|
||||
'$description' => 'This event triggers when a document is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a document is updated.'
|
||||
'$description' => 'This event triggers when a document is updated.',
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
@@ -99,8 +99,8 @@ return [
|
||||
'$description' => 'This event triggers when an index is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when an index is deleted.'
|
||||
]
|
||||
'$description' => 'This event triggers when an index is deleted.',
|
||||
],
|
||||
],
|
||||
'attributes' => [
|
||||
'$model' => Response::MODEL_ATTRIBUTE,
|
||||
@@ -110,28 +110,28 @@ return [
|
||||
'$description' => 'This event triggers when an attribute is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when an attribute is deleted.'
|
||||
]
|
||||
'$description' => 'This event triggers when an attribute is deleted.',
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a collection is created.'
|
||||
'$description' => 'This event triggers when a collection is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a collection is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a collection is updated.',
|
||||
]
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a database is created.'
|
||||
'$description' => 'This event triggers when a database is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a database is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a database is updated.',
|
||||
]
|
||||
],
|
||||
],
|
||||
'buckets' => [
|
||||
'$model' => Response::MODEL_BUCKET,
|
||||
@@ -145,21 +145,21 @@ return [
|
||||
'$description' => 'This event triggers when a file is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a file is deleted.'
|
||||
'$description' => 'This event triggers when a file is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a file is updated.'
|
||||
'$description' => 'This event triggers when a file is updated.',
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a bucket is created.'
|
||||
'$description' => 'This event triggers when a bucket is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a bucket is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a bucket is updated.',
|
||||
]
|
||||
],
|
||||
],
|
||||
'teams' => [
|
||||
'$model' => Response::MODEL_TEAM,
|
||||
@@ -173,24 +173,24 @@ return [
|
||||
'$description' => 'This event triggers when a membership is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a membership is deleted.'
|
||||
'$description' => 'This event triggers when a membership is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a membership is updated.',
|
||||
'status' => [
|
||||
'$description' => 'This event triggers when a team memberships status is updated.'
|
||||
]
|
||||
'$description' => 'This event triggers when a team memberships status is updated.',
|
||||
],
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a bucket is created.'
|
||||
'$description' => 'This event triggers when a bucket is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a bucket is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a bucket is updated.',
|
||||
]
|
||||
],
|
||||
],
|
||||
'functions' => [
|
||||
'$model' => Response::MODEL_FUNCTION,
|
||||
@@ -204,10 +204,10 @@ return [
|
||||
'$description' => 'This event triggers when a deployment is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a deployment is deleted.'
|
||||
'$description' => 'This event triggers when a deployment is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a deployment is updated.'
|
||||
'$description' => 'This event triggers when a deployment is updated.',
|
||||
],
|
||||
],
|
||||
'executions' => [
|
||||
@@ -218,20 +218,20 @@ return [
|
||||
'$description' => 'This event triggers when an execution is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when an execution is deleted.'
|
||||
'$description' => 'This event triggers when an execution is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when an execution is updated.'
|
||||
'$description' => 'This event triggers when an execution is updated.',
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a function is created.'
|
||||
'$description' => 'This event triggers when a function is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a function is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a function is updated.',
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
+553
-553
File diff suppressed because it is too large
Load Diff
+22
-22
@@ -24,7 +24,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'javascript',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-web'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-web'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-web.git',
|
||||
'gitRepoName' => 'sdk-for-web',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -58,7 +58,7 @@ return [
|
||||
'source' => 'https://github.com/appwrite/todo-with-svelte',
|
||||
'url' => 'https://appwrite-todo-with-svelte.vercel.app/',
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'flutter',
|
||||
@@ -72,7 +72,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'dart',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-flutter'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-flutter'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-flutter.git',
|
||||
'gitRepoName' => 'sdk-for-flutter',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -90,7 +90,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'swift',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-apple'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-apple'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-apple.git',
|
||||
'gitRepoName' => 'sdk-for-apple',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -125,7 +125,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'kotlin',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-android'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-android'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-android.git',
|
||||
'gitRepoName' => 'sdk-for-android',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -147,7 +147,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'graphql',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-graphql'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-graphql'),
|
||||
'gitUrl' => '',
|
||||
'gitRepoName' => '',
|
||||
'gitUserName' => '',
|
||||
@@ -166,7 +166,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'http',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-rest'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-rest'),
|
||||
'gitUrl' => '',
|
||||
'gitRepoName' => '',
|
||||
'gitUserName' => '',
|
||||
@@ -194,7 +194,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_CONSOLE,
|
||||
'prism' => 'javascript',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/console-web'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/console-web'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-console.git',
|
||||
'gitBranch' => 'main',
|
||||
'gitRepoName' => 'sdk-for-console',
|
||||
@@ -212,7 +212,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CONSOLE,
|
||||
'prism' => 'bash',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/console-cli'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/console-cli'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-cli.git',
|
||||
'gitRepoName' => 'sdk-for-cli',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -240,7 +240,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'javascript',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-nodejs'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-nodejs'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-node.git',
|
||||
'gitRepoName' => 'sdk-for-node',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -258,7 +258,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'typescript',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-deno'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-deno'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-deno.git',
|
||||
'gitRepoName' => 'sdk-for-deno',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -276,7 +276,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'php',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-php'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-php'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-php.git',
|
||||
'gitRepoName' => 'sdk-for-php',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -294,7 +294,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'python',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-python'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-python'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-python.git',
|
||||
'gitRepoName' => 'sdk-for-python',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -312,7 +312,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'ruby',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-ruby'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-ruby'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-ruby.git',
|
||||
'gitRepoName' => 'sdk-for-ruby',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -330,7 +330,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'go',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-go'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-go'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-go.git',
|
||||
'gitRepoName' => 'sdk-for-go',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -348,7 +348,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'java',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-java'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-java'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-java.git',
|
||||
'gitRepoName' => 'sdk-for-java',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -366,7 +366,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'csharp',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-dotnet'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-dotnet'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-dotnet.git',
|
||||
'gitRepoName' => 'sdk-for-dotnet',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -384,7 +384,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'dart',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-dart'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-dart'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-dart.git',
|
||||
'gitRepoName' => 'sdk-for-dart',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -402,7 +402,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'kotlin',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-kotlin'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-kotlin'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-kotlin.git',
|
||||
'gitRepoName' => 'sdk-for-kotlin',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -424,7 +424,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'swift',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-swift'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-swift'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-swift.git',
|
||||
'gitRepoName' => 'sdk-for-swift',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -442,7 +442,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'graphql',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-graphql'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-graphql'),
|
||||
'gitUrl' => '',
|
||||
'gitRepoName' => '',
|
||||
'gitUserName' => '',
|
||||
@@ -461,7 +461,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'http',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-rest'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-rest'),
|
||||
'gitUrl' => '',
|
||||
'gitRepoName' => '',
|
||||
'gitUserName' => '',
|
||||
|
||||
@@ -69,7 +69,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'box' => [
|
||||
'name' => 'Box',
|
||||
@@ -79,7 +79,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'dailymotion' => [
|
||||
'name' => 'Dailymotion',
|
||||
@@ -89,7 +89,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'discord' => [
|
||||
'name' => 'Discord',
|
||||
@@ -219,7 +219,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'paypalSandbox' => [
|
||||
'name' => 'PayPal',
|
||||
@@ -229,7 +229,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => true,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'podio' => [
|
||||
'name' => 'Podio',
|
||||
@@ -279,7 +279,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'tradeshift' => [
|
||||
'name' => 'Tradeshift',
|
||||
@@ -319,7 +319,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'yahoo' => [
|
||||
'name' => 'Yahoo',
|
||||
|
||||
@@ -5,5 +5,5 @@ return [
|
||||
'name' => 'Default',
|
||||
'default' => true,
|
||||
'disabled' => false,
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* List of Appwrite Cloud Functions supported runtimes
|
||||
*/
|
||||
|
||||
use Utopia\App;
|
||||
use Appwrite\Runtimes\Runtimes;
|
||||
use Utopia\App;
|
||||
|
||||
$runtimes = new Runtimes('v2');
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ return [ // List of publicly visible scopes
|
||||
'indexes.write' => [
|
||||
'description' => 'Access to create, update, and delete your project\'s database collection\'s indexes',
|
||||
],
|
||||
'documents.read' => [
|
||||
'documents.read' => [
|
||||
'description' => 'Access to read your project\'s database documents',
|
||||
],
|
||||
'documents.write' => [
|
||||
|
||||
@@ -66,8 +66,8 @@ return [
|
||||
'optional' => true,
|
||||
'icon' => '/images/services/databases.png',
|
||||
'globalAttributes' => [
|
||||
'databaseId'
|
||||
]
|
||||
'databaseId',
|
||||
],
|
||||
],
|
||||
'locale' => [
|
||||
'key' => 'locale',
|
||||
|
||||
+76
-76
@@ -14,7 +14,7 @@ return [
|
||||
'default' => 'production',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_LOCALE',
|
||||
@@ -23,7 +23,7 @@ return [
|
||||
'default' => 'en',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_OPTIONS_ABUSE',
|
||||
@@ -32,7 +32,7 @@ return [
|
||||
'default' => 'enabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_OPTIONS_FORCE_HTTPS',
|
||||
@@ -41,7 +41,7 @@ return [
|
||||
'default' => 'disabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_OPENSSL_KEY_V1',
|
||||
@@ -50,7 +50,7 @@ return [
|
||||
'default' => 'your-secret-key',
|
||||
'required' => true,
|
||||
'question' => 'Choose a secret API key, make sure to make a backup of your key in a secure location',
|
||||
'filter' => 'token'
|
||||
'filter' => 'token',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DOMAIN',
|
||||
@@ -59,7 +59,7 @@ return [
|
||||
'default' => 'localhost',
|
||||
'required' => true,
|
||||
'question' => 'Enter your Appwrite hostname',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DOMAIN_TARGET',
|
||||
@@ -67,8 +67,8 @@ return [
|
||||
'introduction' => '',
|
||||
'default' => 'localhost',
|
||||
'required' => true,
|
||||
'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.' . PHP_EOL . 'You can use the same value as used for the Appwrite hostname.',
|
||||
'filter' => 'domainTarget'
|
||||
'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.'.PHP_EOL.'You can use the same value as used for the Appwrite hostname.',
|
||||
'filter' => 'domainTarget',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_CONSOLE_WHITELIST_ROOT',
|
||||
@@ -77,7 +77,7 @@ return [
|
||||
'default' => 'enabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_CONSOLE_WHITELIST_EMAILS',
|
||||
@@ -86,7 +86,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
// [
|
||||
// 'name' => '_APP_CONSOLE_WHITELIST_DOMAINS',
|
||||
@@ -103,7 +103,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SYSTEM_EMAIL_NAME',
|
||||
@@ -112,7 +112,7 @@ return [
|
||||
'default' => 'Appwrite',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SYSTEM_EMAIL_ADDRESS',
|
||||
@@ -121,7 +121,7 @@ return [
|
||||
'default' => 'team@appwrite.io',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SYSTEM_RESPONSE_FORMAT',
|
||||
@@ -130,7 +130,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SYSTEM_SECURITY_EMAIL_ADDRESS',
|
||||
@@ -139,7 +139,7 @@ return [
|
||||
'default' => 'certs@appwrite.io',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_USAGE_STATS',
|
||||
@@ -148,7 +148,7 @@ return [
|
||||
'default' => 'enabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_LOGGING_PROVIDER',
|
||||
@@ -157,7 +157,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_LOGGING_CONFIG',
|
||||
@@ -166,7 +166,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_USAGE_AGGREGATION_INTERVAL',
|
||||
@@ -175,7 +175,7 @@ return [
|
||||
'default' => '30',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_USAGE_TIMESERIES_INTERVAL',
|
||||
@@ -184,7 +184,7 @@ return [
|
||||
'default' => '30',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_USAGE_DATABASE_INTERVAL',
|
||||
@@ -193,7 +193,7 @@ return [
|
||||
'default' => '900',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_WORKER_PER_CORE',
|
||||
@@ -202,8 +202,8 @@ return [
|
||||
'default' => 6,
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
]
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -217,7 +217,7 @@ return [
|
||||
'default' => 'redis',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_REDIS_PORT',
|
||||
@@ -226,7 +226,7 @@ return [
|
||||
'default' => '6379',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_REDIS_USER',
|
||||
@@ -235,7 +235,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_REDIS_PASS',
|
||||
@@ -244,7 +244,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -259,7 +259,7 @@ return [
|
||||
'default' => 'mariadb',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_PORT',
|
||||
@@ -268,7 +268,7 @@ return [
|
||||
'default' => '3306',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_SCHEMA',
|
||||
@@ -277,7 +277,7 @@ return [
|
||||
'default' => 'appwrite',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_USER',
|
||||
@@ -286,7 +286,7 @@ return [
|
||||
'default' => 'user',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_PASS',
|
||||
@@ -295,7 +295,7 @@ return [
|
||||
'default' => 'password',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => 'password'
|
||||
'filter' => 'password',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_ROOT_PASS',
|
||||
@@ -304,7 +304,7 @@ return [
|
||||
'default' => 'rootsecretpassword',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => 'password'
|
||||
'filter' => 'password',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -319,7 +319,7 @@ return [
|
||||
'default' => 'influxdb',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_INFLUXDB_PORT',
|
||||
@@ -328,7 +328,7 @@ return [
|
||||
'default' => '8086',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -343,7 +343,7 @@ return [
|
||||
'default' => 'telegraf',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STATSD_PORT',
|
||||
@@ -352,7 +352,7 @@ return [
|
||||
'default' => '8125',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -367,7 +367,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_PORT',
|
||||
@@ -376,7 +376,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_SECURE',
|
||||
@@ -385,7 +385,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_USERNAME',
|
||||
@@ -394,7 +394,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_PASSWORD',
|
||||
@@ -403,7 +403,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -418,7 +418,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMS_FROM',
|
||||
@@ -427,7 +427,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -442,7 +442,7 @@ return [
|
||||
'default' => '30000000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STORAGE_PREVIEW_LIMIT',
|
||||
@@ -451,7 +451,7 @@ return [
|
||||
'default' => '20000000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STORAGE_ANTIVIRUS',
|
||||
@@ -460,7 +460,7 @@ return [
|
||||
'default' => 'disabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STORAGE_ANTIVIRUS_HOST',
|
||||
@@ -469,7 +469,7 @@ return [
|
||||
'default' => 'clamav',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STORAGE_ANTIVIRUS_PORT',
|
||||
@@ -478,7 +478,7 @@ return [
|
||||
'default' => '3310',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STORAGE_DEVICE',
|
||||
@@ -661,7 +661,7 @@ return [
|
||||
'default' => '30000000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_TIMEOUT',
|
||||
@@ -670,7 +670,7 @@ return [
|
||||
'default' => '900',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_BUILD_TIMEOUT',
|
||||
@@ -679,7 +679,7 @@ return [
|
||||
'default' => '900',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_CONTAINERS',
|
||||
@@ -688,7 +688,7 @@ return [
|
||||
'default' => '10',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_CPUS',
|
||||
@@ -697,7 +697,7 @@ return [
|
||||
'default' => '0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_MEMORY',
|
||||
@@ -706,7 +706,7 @@ return [
|
||||
'default' => '0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_MEMORY_SWAP',
|
||||
@@ -715,16 +715,16 @@ return [
|
||||
'default' => '0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_RUNTIMES',
|
||||
'description' => "This option allows you to enable or disable runtime environments for cloud functions. Disable unused runtimes to save disk space.\n\nTo enable cloud function runtimes, pass a list of enabled environments separated by a comma.\n\nCurrently, supported environments are: " . \implode(', ', \array_keys(Config::getParam('runtimes'))),
|
||||
'description' => "This option allows you to enable or disable runtime environments for cloud functions. Disable unused runtimes to save disk space.\n\nTo enable cloud function runtimes, pass a list of enabled environments separated by a comma.\n\nCurrently, supported environments are: ".\implode(', ', \array_keys(Config::getParam('runtimes'))),
|
||||
'introduction' => '0.8.0',
|
||||
'default' => 'node-16.0,php-8.0,python-3.9,ruby-3.0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_EXECUTOR_SECRET',
|
||||
@@ -733,7 +733,7 @@ return [
|
||||
'default' => 'your-secret-key',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_EXECUTOR_HOST',
|
||||
@@ -742,7 +742,7 @@ return [
|
||||
'default' => 'http://appwrite-executor/v1',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_EXECUTOR_RUNTIME_NETWORK',
|
||||
@@ -751,7 +751,7 @@ return [
|
||||
'default' => 'appwrite_runtimes',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_ENVS',
|
||||
@@ -760,7 +760,7 @@ return [
|
||||
'default' => 'node-16.0,php-7.4,python-3.9,ruby-3.0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_INACTIVE_THRESHOLD',
|
||||
@@ -769,7 +769,7 @@ return [
|
||||
'default' => '60',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'DOCKERHUB_PULL_USERNAME',
|
||||
@@ -778,7 +778,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'DOCKERHUB_PULL_PASSWORD',
|
||||
@@ -787,7 +787,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'DOCKERHUB_PULL_EMAIL',
|
||||
@@ -796,7 +796,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'OPEN_RUNTIMES_NETWORK',
|
||||
@@ -805,7 +805,7 @@ return [
|
||||
'default' => 'appwrite_runtimes',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -820,7 +820,7 @@ return [
|
||||
'default' => '86400',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_CACHE',
|
||||
@@ -829,7 +829,7 @@ return [
|
||||
'default' => '2592000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_EXECUTION',
|
||||
@@ -838,7 +838,7 @@ return [
|
||||
'default' => '1209600',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_AUDIT',
|
||||
@@ -847,7 +847,7 @@ return [
|
||||
'default' => '1209600',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_ABUSE',
|
||||
@@ -856,7 +856,7 @@ return [
|
||||
'default' => '86400',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_USAGE_HOURLY',
|
||||
@@ -865,7 +865,7 @@ return [
|
||||
'default' => '8640000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -880,7 +880,7 @@ return [
|
||||
'default' => '10',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_GRAPHQL_MAX_COMPLEXITY',
|
||||
@@ -889,7 +889,7 @@ return [
|
||||
'default' => '250',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_GRAPHQL_MAX_DEPTH',
|
||||
@@ -898,7 +898,7 @@ return [
|
||||
'default' => '3',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
+177
-245
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Validator\URL;
|
||||
use Appwrite\URL\URL as URLParse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
@@ -14,23 +13,23 @@ use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\HexColor;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
$avatarCallback = function (string $type, string $code, int $width, int $height, int $quality, Response $response) {
|
||||
|
||||
$code = \strtolower($code);
|
||||
$type = \strtolower($type);
|
||||
$set = Config::getParam('avatar-' . $type, []);
|
||||
$set = Config::getParam('avatar-'.$type, []);
|
||||
|
||||
if (empty($set)) {
|
||||
throw new Exception(Exception::AVATAR_SET_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!\array_key_exists($code, $set)) {
|
||||
if (! \array_key_exists($code, $set)) {
|
||||
throw new Exception(Exception::AVATAR_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
if (! \extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
@@ -38,8 +37,8 @@ $avatarCallback = function (string $type, string $code, int $width, int $height,
|
||||
$path = $set[$code];
|
||||
$type = 'png';
|
||||
|
||||
if (!\is_readable($path)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'File not readable in ' . $path);
|
||||
if (! \is_readable($path)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'File not readable in '.$path);
|
||||
}
|
||||
|
||||
$image = new Image(\file_get_contents($path));
|
||||
@@ -47,10 +46,9 @@ $avatarCallback = function (string $type, string $code, int $width, int $height,
|
||||
$output = (empty($output)) ? $type : $output;
|
||||
$data = $image->output($output, $quality);
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType('image/png')
|
||||
->file($data)
|
||||
;
|
||||
->file($data);
|
||||
unset($image);
|
||||
};
|
||||
|
||||
@@ -67,12 +65,12 @@ App::get('/v1/avatars/credit-cards/:code')
|
||||
->label('sdk.description', '/docs/references/avatars/get-credit-card.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
|
||||
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: ' . \implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))) . '.')
|
||||
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: '.\implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))).'.')
|
||||
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
|
||||
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
|
||||
->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
|
||||
->inject('response')
|
||||
->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('credit-cards', $code, $width, $height, $quality, $response));
|
||||
->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('credit-cards', $code, $width, $height, $quality, $response));
|
||||
|
||||
App::get('/v1/avatars/browsers/:code')
|
||||
->desc('Get Browser Icon')
|
||||
@@ -132,18 +130,17 @@ App::get('/v1/avatars/image')
|
||||
->param('height', 400, new Range(0, 2000), 'Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.', true)
|
||||
->inject('response')
|
||||
->action(function (string $url, int $width, int $height, Response $response) {
|
||||
|
||||
$quality = 80;
|
||||
$output = 'png';
|
||||
$type = 'png';
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
if (! \extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
$fetch = @\file_get_contents($url, false);
|
||||
|
||||
if (!$fetch) {
|
||||
if (! $fetch) {
|
||||
throw new Exception(Exception::AVATAR_IMAGE_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -158,10 +155,9 @@ App::get('/v1/avatars/image')
|
||||
$data = $image->output($output, $quality);
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType('image/png')
|
||||
->file($data)
|
||||
;
|
||||
->file($data);
|
||||
unset($image);
|
||||
});
|
||||
|
||||
@@ -181,14 +177,13 @@ App::get('/v1/avatars/favicon')
|
||||
->param('url', '', new URL(['http', 'https']), 'Website URL which you want to fetch the favicon from.')
|
||||
->inject('response')
|
||||
->action(function (string $url, Response $response) {
|
||||
|
||||
$width = 56;
|
||||
$height = 56;
|
||||
$quality = 80;
|
||||
$output = 'png';
|
||||
$type = 'png';
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
if (! \extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
@@ -210,7 +205,7 @@ App::get('/v1/avatars/favicon')
|
||||
|
||||
\curl_close($curl);
|
||||
|
||||
if (!$html) {
|
||||
if (! $html) {
|
||||
throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED);
|
||||
}
|
||||
|
||||
@@ -261,7 +256,7 @@ App::get('/v1/avatars/favicon')
|
||||
if (empty($outputHref) || empty($outputExt)) {
|
||||
$default = \parse_url($url);
|
||||
|
||||
$outputHref = $default['scheme'] . '://' . $default['host'] . '/favicon.ico';
|
||||
$outputHref = $default['scheme'].'://'.$default['host'].'/favicon.ico';
|
||||
$outputExt = 'ico';
|
||||
}
|
||||
|
||||
@@ -272,15 +267,14 @@ App::get('/v1/avatars/favicon')
|
||||
throw new Exception(Exception::AVATAR_ICON_NOT_FOUND, 'Favicon not found');
|
||||
}
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType('image/x-icon')
|
||||
->file($data)
|
||||
;
|
||||
->file($data);
|
||||
}
|
||||
|
||||
$fetch = @\file_get_contents($outputHref, false);
|
||||
|
||||
if (!$fetch) {
|
||||
if (! $fetch) {
|
||||
throw new Exception(Exception::AVATAR_ICON_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -290,10 +284,9 @@ App::get('/v1/avatars/favicon')
|
||||
$data = $image->output($output, $quality);
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType('image/png')
|
||||
->file($data)
|
||||
;
|
||||
->file($data);
|
||||
unset($image);
|
||||
});
|
||||
|
||||
@@ -314,7 +307,6 @@ App::get('/v1/avatars/qr')
|
||||
->param('download', false, new Boolean(true), 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true)
|
||||
->inject('response')
|
||||
->action(function (string $text, int $size, int $margin, bool $download, Response $response) {
|
||||
|
||||
$download = ($download === '1' || $download === 'true' || $download === 1 || $download === true);
|
||||
$options = new QROptions([
|
||||
'addQuietzone' => true,
|
||||
@@ -332,10 +324,9 @@ App::get('/v1/avatars/qr')
|
||||
$image->crop((int) $size, (int) $size);
|
||||
|
||||
$response
|
||||
->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
|
||||
->setContentType('image/png')
|
||||
->send($image->output('png', 9))
|
||||
;
|
||||
->send($image->output('png', 9));
|
||||
});
|
||||
|
||||
App::get('/v1/avatars/initials')
|
||||
@@ -357,17 +348,16 @@ App::get('/v1/avatars/initials')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->action(function (string $name, int $width, int $height, string $background, Response $response, Document $user) {
|
||||
|
||||
$themes = [
|
||||
['background' => '#FFA1CE'], // Default (Pink)
|
||||
['background' => '#FDC584'], // Orange
|
||||
['background' => '#94DBD1'], // Green
|
||||
['background' => '#A1C4FF'], // Blue
|
||||
['background' => '#FFA1CE'], // Pink
|
||||
['background' => '#CBB1FC'] // Purple
|
||||
['background' => '#CBB1FC'], // Purple
|
||||
];
|
||||
|
||||
$name = (!empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', ''));
|
||||
$name = (! empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', ''));
|
||||
$words = \explode(' ', \strtoupper($name));
|
||||
// if there is no space, try to split by `_` underscore
|
||||
$words = (count($words) == 1) ? \explode('_', \strtoupper($name)) : $words;
|
||||
@@ -389,7 +379,7 @@ App::get('/v1/avatars/initials')
|
||||
// Wrap rand value to avoid out of range
|
||||
$rand = ($rand > \count($themes) - 1) ? $rand % \count($themes) : $rand;
|
||||
|
||||
$background = (!empty($background)) ? '#' . $background : $themes[$rand]['background'];
|
||||
$background = (! empty($background)) ? '#'.$background : $themes[$rand]['background'];
|
||||
|
||||
$image = new \Imagick();
|
||||
$punch = new \Imagick();
|
||||
@@ -398,8 +388,8 @@ App::get('/v1/avatars/initials')
|
||||
|
||||
$punch->newImage($width, $height, 'transparent');
|
||||
|
||||
$draw->setFont(__DIR__ . "/../../assets/fonts/poppins-v9-latin-500.ttf");
|
||||
$image->setFont(__DIR__ . "/../../assets/fonts/poppins-v9-latin-500.ttf");
|
||||
$draw->setFont(__DIR__.'/../../assets/fonts/poppins-v9-latin-500.ttf');
|
||||
$image->setFont(__DIR__.'/../../assets/fonts/poppins-v9-latin-500.ttf');
|
||||
|
||||
$draw->setFillColor(new ImagickPixel('black'));
|
||||
$draw->setFontSize($fontSize);
|
||||
@@ -411,14 +401,13 @@ App::get('/v1/avatars/initials')
|
||||
$punch->negateImage(true, Imagick::CHANNEL_ALPHA);
|
||||
|
||||
$image->newImage($width, $height, $background);
|
||||
$image->setImageFormat("png");
|
||||
$image->setImageFormat('png');
|
||||
$image->compositeImage($punch, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
|
||||
|
||||
//$image->setImageCompressionQuality(9 - round(($quality / 100) * 9));
|
||||
|
||||
$response
|
||||
->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
|
||||
->setContentType('image/png')
|
||||
->file($image->getImageBlob())
|
||||
;
|
||||
->file($image->getImageBlob());
|
||||
});
|
||||
|
||||
+215
-270
File diff suppressed because it is too large
Load Diff
+238
-257
@@ -1,21 +1,21 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Auth\Validator\Phone;
|
||||
use Utopia\Validator\Domain as DomainValidator;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Domains\Domain;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Utopia\Domains\Registrar;
|
||||
use Utopia\Domains\Contact;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Domains\Registrar;
|
||||
use Utopia\Validator\Domain as DomainValidator;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
App::init()
|
||||
@@ -28,7 +28,7 @@ App::init()
|
||||
});
|
||||
|
||||
App::post('/v1/domains/suggest')
|
||||
->desc("Suggest domain names")
|
||||
->desc('Suggest domain names')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -41,15 +41,14 @@ App::post('/v1/domains/suggest')
|
||||
->inject('response')
|
||||
->inject('registrar')
|
||||
->action(function (string $domain, $response, $registrar) {
|
||||
|
||||
$domain = new Domain($domain);
|
||||
$suggestions = $registrar->suggest([$domain->getName()], [$domain->getTLD()]);
|
||||
$domain = new Domain($domain);
|
||||
$suggestions = $registrar->suggest([$domain->getName()], [$domain->getTLD()]);
|
||||
|
||||
$response->dynamic(new Document(["domains" => $suggestions]), Response::MODEL_DOMAIN_LIST);
|
||||
$response->dynamic(new Document(['domains' => $suggestions]), Response::MODEL_DOMAIN_LIST);
|
||||
});
|
||||
|
||||
App::post('/v1/domains/available')
|
||||
->desc("Checks if a domain is available for registration")
|
||||
->desc('Checks if a domain is available for registration')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -62,17 +61,16 @@ App::post('/v1/domains/available')
|
||||
->inject('response')
|
||||
->inject('registrar')
|
||||
->action(function (string $domain, $response, $registrar) {
|
||||
|
||||
$domain = [
|
||||
"domain" => $domain,
|
||||
"available" => $registrar->available($domain)
|
||||
];
|
||||
$domain = [
|
||||
'domain' => $domain,
|
||||
'available' => $registrar->available($domain),
|
||||
];
|
||||
|
||||
$response->dynamic(new Document(["domain" => $domain]), Response::MODEL_DOMAIN);
|
||||
$response->dynamic(new Document(['domain' => $domain]), Response::MODEL_DOMAIN);
|
||||
});
|
||||
|
||||
App::post('/v1/domains')
|
||||
->desc("Create a domain for 3rd party registrar, prompt to assign nameservers")
|
||||
->desc('Create a domain for 3rd party registrar, prompt to assign nameservers')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -87,62 +85,61 @@ App::post('/v1/domains')
|
||||
->inject('dbForConsole')
|
||||
->inject('registrar')
|
||||
->action(function (
|
||||
string $projectId,
|
||||
string $domain,
|
||||
Response $response,
|
||||
Database $dbForConsole,
|
||||
string $projectId,
|
||||
string $domain,
|
||||
Response $response,
|
||||
Database $dbForConsole,
|
||||
Registrar $registrar
|
||||
) {
|
||||
) {
|
||||
if (! $registrar->available($domain)) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
if(!$registrar->available($domain)) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
$document = $dbForConsole->findOne('domains', [
|
||||
Query::equal('domain', [$domain]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
|
||||
$document = $dbForConsole->findOne('domains', [
|
||||
Query::equal('domain', [$domain]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
if ($document && ! $document->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
if ($document && !$document->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
$domain = new Domain($domain);
|
||||
|
||||
$domain = new Domain($domain);
|
||||
$domain = new Document([
|
||||
'$id' => ID::unique(),
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'projectInternalId' => $project->getInternalId(),
|
||||
'projectId' => $project->getId(),
|
||||
'domain' => $domain->get(),
|
||||
'tld' => $domain->getSuffix(),
|
||||
'registerable' => $domain->getRegisterable(),
|
||||
'verification' => false,
|
||||
'certificateId' => null,
|
||||
'registered' => false,
|
||||
]);
|
||||
|
||||
$domain = new Document([
|
||||
'$id' => ID::unique(),
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'projectInternalId' => $project->getInternalId(),
|
||||
'projectId' => $project->getId(),
|
||||
'domain' => $domain->get(),
|
||||
'tld' => $domain->getSuffix(),
|
||||
'registerable' => $domain->getRegisterable(),
|
||||
'verification' => false,
|
||||
'certificateId' => null,
|
||||
'registered' => false,
|
||||
]);
|
||||
$domain = $dbForConsole->createDocument('domains', $domain);
|
||||
|
||||
$domain = $dbForConsole->createDocument('domains', $domain);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($domain, Response::MODEL_DOMAIN);
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($domain, Response::MODEL_DOMAIN);
|
||||
});
|
||||
|
||||
App::post('/v1/domains/purchase')
|
||||
->desc("Purchase, create and domain assign nameservers")
|
||||
->desc('Purchase, create and domain assign nameservers')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -169,8 +166,8 @@ App::post('/v1/domains/purchase')
|
||||
->inject('dbForConsole')
|
||||
->inject('registrar')
|
||||
->action(function (
|
||||
string $projectId,
|
||||
string $domain,
|
||||
string $projectId,
|
||||
string $domain,
|
||||
string $firstname,
|
||||
string $lastname,
|
||||
string $phone,
|
||||
@@ -183,88 +180,81 @@ App::post('/v1/domains/purchase')
|
||||
string $country,
|
||||
string $postalcode,
|
||||
string $org,
|
||||
Response $response,
|
||||
Database $dbForConsole,
|
||||
Response $response,
|
||||
Database $dbForConsole,
|
||||
Registrar $registrar
|
||||
) {
|
||||
) {
|
||||
if (! $registrar->available($domain)) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
if(!$registrar->available($domain)) {
|
||||
throw new Exception();
|
||||
}
|
||||
$contact = new Contact(
|
||||
$firstname,
|
||||
$lastname,
|
||||
$phone,
|
||||
$email,
|
||||
$address1,
|
||||
$address2,
|
||||
$address3,
|
||||
$city,
|
||||
$state,
|
||||
$country,
|
||||
$postalcode,
|
||||
$org,
|
||||
''
|
||||
);
|
||||
|
||||
|
||||
$contact = new Contact(
|
||||
$firstname,
|
||||
$lastname,
|
||||
$phone,
|
||||
$email,
|
||||
$address1,
|
||||
$address2,
|
||||
$address3,
|
||||
$city,
|
||||
$state,
|
||||
$country,
|
||||
$postalcode,
|
||||
$org,
|
||||
''
|
||||
);
|
||||
try {
|
||||
$registrar->purchase($domain, [$contact]);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
try {
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
$registrar->purchase($domain, [$contact]);
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$document = $dbForConsole->findOne('domains', [
|
||||
Query::equal('domain', [$domain]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
|
||||
throw new Exception();
|
||||
if ($document && ! $document->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
}
|
||||
$domain = new Domain($domain);
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
$domain = new Document([
|
||||
'$id' => ID::unique(),
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'projectInternalId' => $project->getInternalId(),
|
||||
'projectId' => $project->getId(),
|
||||
'domain' => $domain->get(),
|
||||
'tld' => $domain->getSuffix(),
|
||||
'registerable' => $domain->getRegisterable(),
|
||||
'verification' => false,
|
||||
'certificateId' => null,
|
||||
'registered' => true,
|
||||
]);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
$domain = $dbForConsole->createDocument('domains', $domain);
|
||||
|
||||
$document = $dbForConsole->findOne('domains', [
|
||||
Query::equal('domain', [$domain]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
|
||||
if ($document && !$document->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$domain = new Domain($domain);
|
||||
|
||||
$domain = new Document([
|
||||
'$id' => ID::unique(),
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'projectInternalId' => $project->getInternalId(),
|
||||
'projectId' => $project->getId(),
|
||||
'domain' => $domain->get(),
|
||||
'tld' => $domain->getSuffix(),
|
||||
'registerable' => $domain->getRegisterable(),
|
||||
'verification' => false,
|
||||
'certificateId' => null,
|
||||
'registered' => true,
|
||||
]);
|
||||
|
||||
$domain = $dbForConsole->createDocument('domains', $domain);
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($domain, Response::MODEL_DOMAIN);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($domain, Response::MODEL_DOMAIN);
|
||||
});
|
||||
|
||||
App::post('/v1/domains/transfer/in')
|
||||
->desc("Transfer existing domain to Appwrite, and assign nameservers")
|
||||
->desc('Transfer existing domain to Appwrite, and assign nameservers')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -291,97 +281,91 @@ App::post('/v1/domains/transfer/in')
|
||||
->inject('dbForConsole')
|
||||
->inject('registrar')
|
||||
->action(function (
|
||||
string $projectId,
|
||||
string $domain,
|
||||
string $firstname,
|
||||
string $lastname,
|
||||
string $phone,
|
||||
string $email,
|
||||
string $address1,
|
||||
string $address2,
|
||||
string $address3,
|
||||
string $city,
|
||||
string $state,
|
||||
string $country,
|
||||
string $postalcode,
|
||||
string $org,
|
||||
Response $response,
|
||||
Database $dbForConsole,
|
||||
Registrar $registrar
|
||||
string $projectId,
|
||||
string $domain,
|
||||
string $firstname,
|
||||
string $lastname,
|
||||
string $phone,
|
||||
string $email,
|
||||
string $address1,
|
||||
string $address2,
|
||||
string $address3,
|
||||
string $city,
|
||||
string $state,
|
||||
string $country,
|
||||
string $postalcode,
|
||||
string $org,
|
||||
Response $response,
|
||||
Database $dbForConsole,
|
||||
Registrar $registrar
|
||||
) {
|
||||
$contact = new Contact(
|
||||
$firstname,
|
||||
$lastname,
|
||||
$phone,
|
||||
$email,
|
||||
$address1,
|
||||
$address2,
|
||||
$address3,
|
||||
$city,
|
||||
$state,
|
||||
$country,
|
||||
$postalcode,
|
||||
$org,
|
||||
''
|
||||
);
|
||||
|
||||
$contact = new Contact(
|
||||
$firstname,
|
||||
$lastname,
|
||||
$phone,
|
||||
$email,
|
||||
$address1,
|
||||
$address2,
|
||||
$address3,
|
||||
$city,
|
||||
$state,
|
||||
$country,
|
||||
$postalcode,
|
||||
$org,
|
||||
''
|
||||
);
|
||||
try {
|
||||
$registrar->transfer($domain, [$contact]);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
try {
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
$registrar->transfer($domain, [$contact]);
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$document = $dbForConsole->findOne('domains', [
|
||||
Query::equal('domain', [$domain]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
|
||||
throw new Exception();
|
||||
if ($document && ! $document->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
}
|
||||
$domain = new Domain($domain);
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
$domain = new Document([
|
||||
'$id' => ID::unique(),
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'projectInternalId' => $project->getInternalId(),
|
||||
'projectId' => $project->getId(),
|
||||
'domain' => $domain->get(),
|
||||
'tld' => $domain->getSuffix(),
|
||||
'registerable' => $domain->getRegisterable(),
|
||||
'verification' => false,
|
||||
'certificateId' => null,
|
||||
'registered' => true,
|
||||
]);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
$domain = $dbForConsole->createDocument('domains', $domain);
|
||||
|
||||
$document = $dbForConsole->findOne('domains', [
|
||||
Query::equal('domain', [$domain]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
|
||||
if ($document && !$document->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$domain = new Domain($domain);
|
||||
|
||||
$domain = new Document([
|
||||
'$id' => ID::unique(),
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'projectInternalId' => $project->getInternalId(),
|
||||
'projectId' => $project->getId(),
|
||||
'domain' => $domain->get(),
|
||||
'tld' => $domain->getSuffix(),
|
||||
'registerable' => $domain->getRegisterable(),
|
||||
'verification' => false,
|
||||
'certificateId' => null,
|
||||
'registered' => true,
|
||||
]);
|
||||
|
||||
$domain = $dbForConsole->createDocument('domains', $domain);
|
||||
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($domain, Response::MODEL_DOMAIN);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($domain, Response::MODEL_DOMAIN);
|
||||
});
|
||||
|
||||
App::post('/v1/domains/transfer/out')
|
||||
->desc("Start transfer process for domain and generate code for transfer to 3rd party registrar")
|
||||
->desc('Start transfer process for domain and generate code for transfer to 3rd party registrar')
|
||||
->groups(['api', 'domains'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -397,7 +381,7 @@ App::post('/v1/domains/transfer/out')
|
||||
});
|
||||
|
||||
App::get('/v1/domains')
|
||||
->desc("List domains")
|
||||
->desc('List domains')
|
||||
->groups(['api', 'domains'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -410,26 +394,25 @@ App::get('/v1/domains')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$domains = $dbForConsole->find('domains', [
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
Query::limit(5000),
|
||||
]);
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'domains' => $domains,
|
||||
'total' => count($domains),
|
||||
]), Response::MODEL_DOMAIN_LIST);
|
||||
$domains = $dbForConsole->find('domains', [
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
Query::limit(5000),
|
||||
]);
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'domains' => $domains,
|
||||
'total' => count($domains),
|
||||
]), Response::MODEL_DOMAIN_LIST);
|
||||
});
|
||||
|
||||
App::get('/v1/domains/:domainId')
|
||||
->desc("Get domain")
|
||||
->desc('Get domain')
|
||||
->groups(['api', 'domains'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -443,27 +426,26 @@ App::get('/v1/domains/:domainId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
$domain = $dbForConsole->findOne('domains', [
|
||||
Query::equal('_uid', [$domainId]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
|
||||
$domain = $dbForConsole->findOne('domains', [
|
||||
Query::equal('_uid', [$domainId]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
if ($domain === false || $domain->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($domain === false || $domain->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic($domain, Response::MODEL_DOMAIN);
|
||||
$response->dynamic($domain, Response::MODEL_DOMAIN);
|
||||
});
|
||||
|
||||
App::patch('/v1/domains/:domainId/nameservers')
|
||||
->desc("Check namserver records and update them if needed")
|
||||
->desc('Check namserver records and update them if needed')
|
||||
->groups(['api', 'domains'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -476,11 +458,11 @@ App::patch('/v1/domains/:domainId/nameservers')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->action(function () {
|
||||
///Do we need/want?
|
||||
///Do we need/want?
|
||||
});
|
||||
|
||||
App::patch('/v1/domains/:domainId/project')
|
||||
->desc("Move domain to a different project")
|
||||
->desc('Move domain to a different project')
|
||||
->groups(['api', 'domains'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -493,11 +475,11 @@ App::patch('/v1/domains/:domainId/project')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->action(function () {
|
||||
/// WAIT FOR TRANSFER SERVICE.
|
||||
/// WAIT FOR TRANSFER SERVICE.
|
||||
});
|
||||
|
||||
App::delete('/v1/domains/:domainId')
|
||||
->desc("Remove a domain")
|
||||
->desc('Remove a domain')
|
||||
->groups(['api', 'domains'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
@@ -511,25 +493,24 @@ App::delete('/v1/domains/:domainId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
$domain = $dbForConsole->findOne('domains', [
|
||||
Query::equal('_uid', [$domainId]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
|
||||
$domain = $dbForConsole->findOne('domains', [
|
||||
Query::equal('_uid', [$domainId]),
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
if ($domain === false || $domain->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($domain === false || $domain->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_NOT_FOUND);
|
||||
}
|
||||
if ($domain['registered'] === true) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
if($domain['registered'] === true) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
$response->noContent();
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
@@ -8,44 +8,43 @@ use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Validator\Event as ValidatorEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Task\Validator\Cron;
|
||||
use Appwrite\Usage\Stats;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Executions;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Functions;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Variables;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Cron\CronExpression;
|
||||
use Executor\Executor;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Appwrite\Usage\Stats;
|
||||
use Utopia\Storage\Device;
|
||||
use Utopia\Storage\Validator\File;
|
||||
use Utopia\Storage\Validator\FileExt;
|
||||
use Utopia\Storage\Validator\FileSize;
|
||||
use Utopia\Storage\Validator\Upload;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Swoole\Request;
|
||||
use Appwrite\Task\Validator\Cron;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Executions;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Functions;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Variables;
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Config\Config;
|
||||
use Cron\CronExpression;
|
||||
use Executor\Executor;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
include_once __DIR__ . '/../shared/api.php';
|
||||
include_once __DIR__.'/../shared/api.php';
|
||||
|
||||
App::post('/v1/functions')
|
||||
->groups(['api', 'functions'])
|
||||
@@ -63,9 +62,9 @@ App::post('/v1/functions')
|
||||
->label('sdk.response.model', Response::MODEL_FUNCTION)
|
||||
->param('functionId', '', new CustomId(), 'Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. 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('name', '', new Text(128), 'Function name. Max length: 128 chars.')
|
||||
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.')
|
||||
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 64 characters long.')
|
||||
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
|
||||
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
|
||||
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.', true)
|
||||
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
|
||||
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.', true)
|
||||
->param('enabled', true, new Boolean(), 'Is function enabled?', true)
|
||||
@@ -75,9 +74,8 @@ App::post('/v1/functions')
|
||||
->inject('user')
|
||||
->inject('events')
|
||||
->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance) {
|
||||
|
||||
$cron = !empty($schedule) ? new CronExpression($schedule) : null;
|
||||
$next = !empty($schedule) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
$cron = ! empty($schedule) ? new CronExpression($schedule) : null;
|
||||
$next = ! empty($schedule) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
|
||||
$functionId = ($functionId == 'unique()') ? ID::unique() : $functionId;
|
||||
$function = $dbForProject->createDocument('functions', new Document([
|
||||
@@ -93,7 +91,7 @@ App::post('/v1/functions')
|
||||
'schedulePrevious' => null,
|
||||
'scheduleNext' => $next,
|
||||
'timeout' => $timeout,
|
||||
'search' => implode(' ', [$functionId, $name, $runtime])
|
||||
'search' => implode(' ', [$functionId, $name, $runtime]),
|
||||
]));
|
||||
|
||||
if ($next) {
|
||||
@@ -125,15 +123,14 @@ App::get('/v1/functions')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FUNCTION_LIST)
|
||||
->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Functions::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Functions::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -173,17 +170,17 @@ App::get('/v1/functions/runtimes')
|
||||
->label('sdk.response.model', Response::MODEL_RUNTIME_LIST)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$runtimes = Config::getParam('runtimes');
|
||||
|
||||
$runtimes = array_map(function ($key) use ($runtimes) {
|
||||
$runtimes[$key]['$id'] = $key;
|
||||
|
||||
return $runtimes[$key];
|
||||
}, array_keys($runtimes));
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => count($runtimes),
|
||||
'runtimes' => $runtimes
|
||||
'runtimes' => $runtimes,
|
||||
]), Response::MODEL_RUNTIME_LIST);
|
||||
});
|
||||
|
||||
@@ -226,7 +223,6 @@ App::get('/v1/functions/:functionId/usage')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -314,7 +310,7 @@ App::get('/v1/functions/:functionId/usage')
|
||||
'buildsTotal' => $stats["builds.$functionId.compute.total"] ?? [],
|
||||
'buildsFailure' => $stats["builds.$functionId.compute.failure"] ?? [],
|
||||
'buildsSuccess' => $stats["builds.$functionId.compute.success"] ?? [],
|
||||
'buildsTime' => $stats["builds.$functionId.compute.time" ?? []]
|
||||
'buildsTime' => $stats["builds.$functionId.compute.time" ?? []],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -335,7 +331,6 @@ App::get('/v1/functions/usage')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$usage = [];
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
$periods = [
|
||||
@@ -440,8 +435,8 @@ App::put('/v1/functions/:functionId')
|
||||
->label('sdk.response.model', Response::MODEL_FUNCTION)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
|
||||
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.')
|
||||
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
|
||||
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 64 characters long.')
|
||||
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.', true)
|
||||
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
|
||||
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true)
|
||||
->param('enabled', true, new Boolean(), 'Is function enabled?', true)
|
||||
@@ -451,15 +446,14 @@ App::put('/v1/functions/:functionId')
|
||||
->inject('user')
|
||||
->inject('events')
|
||||
->action(function (string $functionId, string $name, array $execute, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$cron = !empty($schedule) ? new CronExpression($schedule) : null;
|
||||
$next = !empty($schedule) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
$cron = ! empty($schedule) ? new CronExpression($schedule) : null;
|
||||
$next = ! empty($schedule) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
|
||||
$enabled ??= $function->getAttribute('enabled', true);
|
||||
|
||||
@@ -512,7 +506,6 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
->inject('project')
|
||||
->inject('events')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Document $project, Event $events) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', ''));
|
||||
@@ -534,7 +527,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
}
|
||||
|
||||
$function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
|
||||
'deployment' => $deployment->getId()
|
||||
'deployment' => $deployment->getId(),
|
||||
])));
|
||||
|
||||
$events
|
||||
@@ -563,14 +556,13 @@ App::delete('/v1/functions/:functionId')
|
||||
->inject('deletes')
|
||||
->inject('events')
|
||||
->action(function (string $functionId, Response $response, Database $dbForProject, Delete $deletes, Event $events) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteDocument('functions', $function->getId())) {
|
||||
if (! $dbForProject->deleteDocument('functions', $function->getId())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove function from DB');
|
||||
}
|
||||
|
||||
@@ -611,7 +603,6 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
->inject('deviceFunctions')
|
||||
->inject('deviceLocal')
|
||||
->action(function (string $functionId, string $entrypoint, mixed $code, bool $activate, Request $request, Response $response, Database $dbForProject, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -638,7 +629,7 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
$fileTmpName = (\is_array($file['tmp_name']) && isset($file['tmp_name'][0])) ? $file['tmp_name'][0] : $file['tmp_name'];
|
||||
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
|
||||
|
||||
if (!$fileExt->isValid($file['name'])) { // Check if file type is allowed
|
||||
if (! $fileExt->isValid($file['name'])) { // Check if file type is allowed
|
||||
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
@@ -647,7 +638,7 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
$chunk = 1;
|
||||
$chunks = 1;
|
||||
|
||||
if (!empty($contentRange)) {
|
||||
if (! empty($contentRange)) {
|
||||
$start = $request->getContentRangeStart();
|
||||
$end = $request->getContentRangeEnd();
|
||||
$fileSize = $request->getContentRangeSize();
|
||||
@@ -666,22 +657,22 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
}
|
||||
}
|
||||
|
||||
if (!$fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit
|
||||
if (! $fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE);
|
||||
}
|
||||
|
||||
if (!$upload->isValid($fileTmpName)) {
|
||||
if (! $upload->isValid($fileTmpName)) {
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE);
|
||||
}
|
||||
|
||||
// Save to storage
|
||||
$fileSize ??= $deviceLocal->getFileSize($fileTmpName);
|
||||
$path = $deviceFunctions->getPath($deploymentId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$path = $deviceFunctions->getPath($deploymentId.'.'.\pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
$metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)];
|
||||
if (!$deployment->isEmpty()) {
|
||||
if (! $deployment->isEmpty()) {
|
||||
$chunks = $deployment->getAttribute('chunksTotal', 1);
|
||||
$metadata = $deployment->getAttribute('metadata', []);
|
||||
if ($chunk === -1) {
|
||||
@@ -703,7 +694,7 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
$activeDeployments = $dbForProject->find('deployments', [
|
||||
Query::equal('activate', [true]),
|
||||
Query::equal('resourceId', [$functionId]),
|
||||
Query::equal('resourceType', ['functions'])
|
||||
Query::equal('resourceType', ['functions']),
|
||||
]);
|
||||
|
||||
foreach ($activeDeployments as $activeDeployment) {
|
||||
@@ -791,12 +782,11 @@ App::get('/v1/functions/:functionId/deployments')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DEPLOYMENT_LIST)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Deployments::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -805,7 +795,7 @@ App::get('/v1/functions/:functionId/deployments')
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -863,7 +853,6 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -909,7 +898,6 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
->inject('events')
|
||||
->inject('deviceFunctions')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Device $deviceFunctions) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
@@ -925,7 +913,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
}
|
||||
|
||||
if ($deviceFunctions->delete($deployment->getAttribute('path', ''))) {
|
||||
if (!$dbForProject->deleteDocument('deployments', $deployment->getId())) {
|
||||
if (! $dbForProject->deleteDocument('deployments', $deployment->getId())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove deployment from DB');
|
||||
}
|
||||
}
|
||||
@@ -968,7 +956,6 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
||||
->inject('project')
|
||||
->inject('events')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
@@ -1006,8 +993,6 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
|
||||
|
||||
App::post('/v1/functions/:functionId/executions')
|
||||
->groups(['api', 'functions'])
|
||||
->desc('Create Execution')
|
||||
@@ -1034,11 +1019,10 @@ App::post('/v1/functions/:functionId/executions')
|
||||
->inject('usage')
|
||||
->inject('mode')
|
||||
->action(function (string $functionId, string $data, bool $async, Response $response, Document $project, Database $dbForProject, Document $user, Event $events, Stats $usage, string $mode) {
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
|
||||
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
if ($function->isEmpty() || ! $function->getAttribute('enabled')) {
|
||||
if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
@@ -1048,7 +1032,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
|
||||
|
||||
if (\is_null($runtime)) {
|
||||
throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||
throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "'.$function->getAttribute('runtime', '').'" is not supported');
|
||||
}
|
||||
|
||||
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
|
||||
@@ -1073,7 +1057,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
|
||||
$validator = new Authorization('execute');
|
||||
|
||||
if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function
|
||||
if (! $validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription());
|
||||
}
|
||||
|
||||
@@ -1082,7 +1066,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
/** @var Document $execution */
|
||||
$execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', new Document([
|
||||
'$id' => $executionId,
|
||||
'$permissions' => !$user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [],
|
||||
'$permissions' => ! $user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [],
|
||||
'functionId' => $function->getId(),
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'trigger' => 'http', // http / schedule / event
|
||||
@@ -1095,7 +1079,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
])));
|
||||
|
||||
$jwt = ''; // initialize
|
||||
if (!$user->isEmpty()) { // If userId exists, generate a JWT for function
|
||||
if (! $user->isEmpty()) { // If userId exists, generate a JWT for function
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$current = new Document();
|
||||
|
||||
@@ -1106,7 +1090,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
}
|
||||
}
|
||||
|
||||
if (!$current->isEmpty()) {
|
||||
if (! $current->isEmpty()) {
|
||||
$jwtObj = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
$jwt = $jwtObj->encode([
|
||||
'userId' => $user->getId(),
|
||||
@@ -1140,6 +1124,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
|
||||
$vars = array_reduce($function['vars'] ?? [], function (array $carry, Document $var) {
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? '';
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
@@ -1181,7 +1166,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
} catch (\Throwable $th) {
|
||||
$interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt()));
|
||||
$execution
|
||||
->setAttribute('duration', (float)$interval->format('%s.%f'))
|
||||
->setAttribute('duration', (float) $interval->format('%s.%f'))
|
||||
->setAttribute('status', 'failed')
|
||||
->setAttribute('statusCode', $th->getCode())
|
||||
->setAttribute('stderr', $th->getMessage());
|
||||
@@ -1201,7 +1186,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
||||
$isAppUser = Auth::isAppUser($roles);
|
||||
|
||||
if (!$isPrivilegedUser && !$isAppUser) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser) {
|
||||
$execution->setAttribute('stdout', '');
|
||||
$execution->setAttribute('stderr', '');
|
||||
}
|
||||
@@ -1223,24 +1208,23 @@ App::get('/v1/functions/:functionId/executions')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_EXECUTION_LIST)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
|
||||
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
if ($function->isEmpty() || ! $function->getAttribute('enabled')) {
|
||||
if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -1270,10 +1254,11 @@ App::get('/v1/functions/:functionId/executions')
|
||||
$roles = Authorization::getRoles();
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
||||
$isAppUser = Auth::isAppUser($roles);
|
||||
if (!$isPrivilegedUser && !$isAppUser) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser) {
|
||||
$results = array_map(function ($execution) {
|
||||
$execution->setAttribute('stdout', '');
|
||||
$execution->setAttribute('stderr', '');
|
||||
|
||||
return $execution;
|
||||
}, $results);
|
||||
}
|
||||
@@ -1301,11 +1286,10 @@ App::get('/v1/functions/:functionId/executions/:executionId')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (string $functionId, string $executionId, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
|
||||
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
if ($function->isEmpty() || ! $function->getAttribute('enabled')) {
|
||||
if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
@@ -1323,7 +1307,7 @@ App::get('/v1/functions/:functionId/executions/:executionId')
|
||||
$roles = Authorization::getRoles();
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
||||
$isAppUser = Auth::isAppUser($roles);
|
||||
if (!$isPrivilegedUser && !$isAppUser) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser) {
|
||||
$execution->setAttribute('stdout', '');
|
||||
$execution->setAttribute('stderr', '');
|
||||
}
|
||||
@@ -1347,7 +1331,7 @@ App::post('/v1/functions/:functionId/variables')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VARIABLE)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.', false)
|
||||
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
|
||||
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: '.Database::LENGTH_KEY.' chars.', false)
|
||||
->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', false)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1468,7 +1452,6 @@ App::put('/v1/functions/:functionId/variables/:variableId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -1487,8 +1470,7 @@ App::put('/v1/functions/:functionId/variables/:variableId')
|
||||
$variable
|
||||
->setAttribute('key', $key)
|
||||
->setAttribute('value', $value ?? $variable->getAttribute('value'))
|
||||
->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key]))
|
||||
;
|
||||
->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key]));
|
||||
|
||||
try {
|
||||
$dbForProject->updateDocument('variables', $variable->getId(), $variable);
|
||||
|
||||
@@ -42,11 +42,11 @@ App::get('/v1/graphql')
|
||||
'query' => $query,
|
||||
];
|
||||
|
||||
if (!empty($operationName)) {
|
||||
if (! empty($operationName)) {
|
||||
$query['operationName'] = $operationName;
|
||||
}
|
||||
|
||||
if (!empty($variables)) {
|
||||
if (! empty($variables)) {
|
||||
$query['variables'] = \json_decode($variables, true);
|
||||
}
|
||||
|
||||
@@ -150,10 +150,11 @@ App::post('/v1/graphql')
|
||||
/**
|
||||
* Execute a GraphQL request
|
||||
*
|
||||
* @param GQLSchema $schema
|
||||
* @param Adapter $promiseAdapter
|
||||
* @param array $query
|
||||
* @param GQLSchema $schema
|
||||
* @param Adapter $promiseAdapter
|
||||
* @param array $query
|
||||
* @return array
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
function execute(
|
||||
@@ -165,7 +166,7 @@ function execute(
|
||||
$maxComplexity = App::getEnv('_APP_GRAPHQL_MAX_COMPLEXITY', 250);
|
||||
$maxDepth = App::getEnv('_APP_GRAPHQL_MAX_DEPTH', 3);
|
||||
|
||||
if (!empty($query) && !isset($query[0])) {
|
||||
if (! empty($query) && ! isset($query[0])) {
|
||||
$query = [$query];
|
||||
}
|
||||
if (empty($query)) {
|
||||
@@ -224,7 +225,7 @@ function execute(
|
||||
/**
|
||||
* Parse an "application/graphql" type request
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
function parseGraphql(Request $request): array
|
||||
@@ -235,8 +236,8 @@ function parseGraphql(Request $request): array
|
||||
/**
|
||||
* Parse an "multipart/form-data" type request
|
||||
*
|
||||
* @param array $query
|
||||
* @param Request $request
|
||||
* @param array $query
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
function parseMultipart(array $query, Request $request): array
|
||||
@@ -248,7 +249,7 @@ function parseMultipart(array $query, Request $request): array
|
||||
foreach ($locations as $location) {
|
||||
$items = &$operations;
|
||||
foreach (\explode('.', $location) as $key) {
|
||||
if (!isset($items[$key]) || !\is_array($items[$key])) {
|
||||
if (! isset($items[$key]) || ! \is_array($items[$key])) {
|
||||
$items[$key] = [];
|
||||
}
|
||||
$items = &$items[$key];
|
||||
@@ -276,7 +277,7 @@ function parseMultipart(array $query, Request $request): array
|
||||
function processResult($result, $debugFlags): array
|
||||
{
|
||||
// Only one query, return the result
|
||||
if (!isset($result[1])) {
|
||||
if (! isset($result[1])) {
|
||||
return $result[0]->toArray($debugFlags);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,9 @@ App::get('/v1/health')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_STATUS)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$output = [
|
||||
'status' => 'pass',
|
||||
'ping' => 0
|
||||
'ping' => 0,
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
@@ -42,8 +41,7 @@ App::get('/v1/health/version')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_VERSION)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->dynamic(new Document([ 'version' => APP_VERSION_STABLE ]), Response::MODEL_HEALTH_VERSION);
|
||||
$response->dynamic(new Document(['version' => APP_VERSION_STABLE]), Response::MODEL_HEALTH_VERSION);
|
||||
});
|
||||
|
||||
App::get('/v1/health/db')
|
||||
@@ -60,14 +58,13 @@ App::get('/v1/health/db')
|
||||
->inject('response')
|
||||
->inject('utopia')
|
||||
->action(function (Response $response, App $utopia) {
|
||||
|
||||
$checkStart = \microtime(true);
|
||||
|
||||
try {
|
||||
$db = $utopia->getResource('db'); /* @var $db PDO */
|
||||
|
||||
// Run a small test to check the connection
|
||||
$statement = $db->prepare("SELECT 1;");
|
||||
$statement = $db->prepare('SELECT 1;');
|
||||
|
||||
$statement->closeCursor();
|
||||
|
||||
@@ -78,7 +75,7 @@ App::get('/v1/health/db')
|
||||
|
||||
$output = [
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
@@ -98,18 +95,17 @@ App::get('/v1/health/cache')
|
||||
->inject('response')
|
||||
->inject('utopia')
|
||||
->action(function (Response $response, App $utopia) {
|
||||
|
||||
$checkStart = \microtime(true);
|
||||
|
||||
$redis = $utopia->getResource('cache');
|
||||
|
||||
if (!$redis->ping(true)) {
|
||||
if (! $redis->ping(true)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Cache is not available');
|
||||
}
|
||||
|
||||
$output = [
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
@@ -128,7 +124,6 @@ App::get('/v1/health/time')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_TIME)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
/*
|
||||
* Code from: @see https://www.beliefmedia.com.au/query-ntp-time-server
|
||||
*/
|
||||
@@ -141,7 +136,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);
|
||||
|
||||
@@ -166,7 +161,7 @@ App::get('/v1/health/time')
|
||||
$output = [
|
||||
'remoteTime' => $timestamp,
|
||||
'localTime' => \time(),
|
||||
'diff' => $diff
|
||||
'diff' => $diff,
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_TIME);
|
||||
@@ -185,8 +180,7 @@ App::get('/v1/health/queue/webhooks')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->dynamic(new Document([ 'size' => Resque::size(Event::WEBHOOK_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
||||
$response->dynamic(new Document(['size' => Resque::size(Event::WEBHOOK_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/queue/logs')
|
||||
@@ -202,8 +196,7 @@ App::get('/v1/health/queue/logs')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->dynamic(new Document([ 'size' => Resque::size(Event::AUDITS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
||||
$response->dynamic(new Document(['size' => Resque::size(Event::AUDITS_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/queue/certificates')
|
||||
@@ -219,8 +212,7 @@ App::get('/v1/health/queue/certificates')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->dynamic(new Document([ 'size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
||||
$response->dynamic(new Document(['size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/queue/functions')
|
||||
@@ -236,8 +228,7 @@ App::get('/v1/health/queue/functions')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->dynamic(new Document([ 'size' => Resque::size(Event::FUNCTIONS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
||||
$response->dynamic(new Document(['size' => Resque::size(Event::FUNCTIONS_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/storage/local')
|
||||
@@ -253,31 +244,30 @@ App::get('/v1/health/storage/local')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_STATUS)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$checkStart = \microtime(true);
|
||||
|
||||
foreach (
|
||||
[
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES,
|
||||
] as $key => $volume
|
||||
) {
|
||||
$device = new Local($volume);
|
||||
|
||||
if (!\is_readable($device->getRoot())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device ' . $key . ' dir is not readable');
|
||||
if (! \is_readable($device->getRoot())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device '.$key.' dir is not readable');
|
||||
}
|
||||
|
||||
if (!\is_writable($device->getRoot())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device ' . $key . ' dir is not writable');
|
||||
if (! \is_writable($device->getRoot())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device '.$key.' dir is not writable');
|
||||
}
|
||||
}
|
||||
|
||||
$output = [
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
@@ -296,10 +286,9 @@ App::get('/v1/health/anti-virus')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_ANTIVIRUS)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$output = [
|
||||
'status' => '',
|
||||
'version' => ''
|
||||
'version' => '',
|
||||
];
|
||||
|
||||
if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'disabled') { // Check if scans are enabled
|
||||
@@ -334,7 +323,6 @@ App::get('/v1/health/stats') // Currently only used internally
|
||||
->inject('register')
|
||||
->inject('deviceFiles')
|
||||
->action(function (Response $response, Registry $register, Device $deviceFiles) {
|
||||
|
||||
$cache = $register->get('cache');
|
||||
|
||||
$cacheStats = $cache->info();
|
||||
@@ -342,7 +330,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()),
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\App;
|
||||
use Utopia\Config\Config;
|
||||
@@ -40,8 +40,8 @@ App::get('/v1/locale')
|
||||
|
||||
if ($record) {
|
||||
$output['countryCode'] = $record['country']['iso_code'];
|
||||
$output['country'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output['continent'] = $locale->getText('continents.' . strtolower($record['continent']['code']), $locale->getText('locale.country.unknown'));
|
||||
$output['country'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output['continent'] = $locale->getText('continents.'.strtolower($record['continent']['code']), $locale->getText('locale.country.unknown'));
|
||||
$output['continentCode'] = $record['continent']['code'];
|
||||
$output['eu'] = (\in_array($record['country']['iso_code'], $eu)) ? true : false;
|
||||
|
||||
@@ -62,9 +62,9 @@ App::get('/v1/locale')
|
||||
}
|
||||
|
||||
$response
|
||||
->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
|
||||
;
|
||||
$response->dynamic(new Document($output), Response::MODEL_LOCALE);
|
||||
});
|
||||
|
||||
@@ -89,7 +89,7 @@ App::get('/v1/locale/countries')
|
||||
|
||||
foreach ($list as $value) {
|
||||
$output[] = new Document([
|
||||
'name' => $locale->getText('countries.' . strtolower($value)),
|
||||
'name' => $locale->getText('countries.'.strtolower($value)),
|
||||
'code' => $value,
|
||||
]);
|
||||
}
|
||||
@@ -121,9 +121,9 @@ App::get('/v1/locale/countries/eu')
|
||||
$output = [];
|
||||
|
||||
foreach ($eu as $code) {
|
||||
if ($locale->getText('countries.' . strtolower($code), false) !== false) {
|
||||
if ($locale->getText('countries.'.strtolower($code), false) !== false) {
|
||||
$output[] = new Document([
|
||||
'name' => $locale->getText('countries.' . strtolower($code)),
|
||||
'name' => $locale->getText('countries.'.strtolower($code)),
|
||||
'code' => $code,
|
||||
]);
|
||||
}
|
||||
@@ -158,11 +158,11 @@ App::get('/v1/locale/countries/phones')
|
||||
\asort($list);
|
||||
|
||||
foreach ($list as $code => $name) {
|
||||
if ($locale->getText('countries.' . strtolower($code), false) !== false) {
|
||||
if ($locale->getText('countries.'.strtolower($code), false) !== false) {
|
||||
$output[] = new Document([
|
||||
'code' => '+' . $list[$code],
|
||||
'code' => '+'.$list[$code],
|
||||
'countryCode' => $code,
|
||||
'countryName' => $locale->getText('countries.' . strtolower($code)),
|
||||
'countryName' => $locale->getText('countries.'.strtolower($code)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -190,7 +190,7 @@ App::get('/v1/locale/continents')
|
||||
|
||||
foreach ($list as $value) {
|
||||
$output[] = new Document([
|
||||
'name' => $locale->getText('continents.' . strtolower($value)),
|
||||
'name' => $locale->getText('continents.'.strtolower($value)),
|
||||
'code' => $value,
|
||||
]);
|
||||
}
|
||||
@@ -224,7 +224,6 @@ App::get('/v1/locale/currencies')
|
||||
$response->dynamic(new Document(['currencies' => $list, 'total' => \count($list)]), Response::MODEL_CURRENCY_LIST);
|
||||
});
|
||||
|
||||
|
||||
App::get('/v1/locale/languages')
|
||||
->desc('List Languages')
|
||||
->groups(['api', 'locale'])
|
||||
|
||||
@@ -5,35 +5,35 @@ use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Validator\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\CNAME;
|
||||
use Utopia\Validator\Domain as DomainValidator;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Utopia\Validator\URL;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\DatetimeValidator;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Registry\Registry;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Domain as DomainValidator;
|
||||
use Utopia\Validator\Hostname;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
App::init()
|
||||
@@ -58,7 +58,7 @@ App::post('/v1/projects')
|
||||
->param('projectId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. 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('name', null, new Text(128), 'Project name. Max length: 128 chars.')
|
||||
->param('teamId', '', new UID(), 'Team unique ID.')
|
||||
->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn($config) => !$config['disabled']))), 'Project Region.', true)
|
||||
->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn ($config) => ! $config['disabled']))), 'Project Region.', true)
|
||||
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
|
||||
->param('logo', '', new Text(1024), 'Project logo.', true)
|
||||
->param('url', '', new URL(), 'Project URL.', true)
|
||||
@@ -72,7 +72,6 @@ App::post('/v1/projects')
|
||||
->inject('dbForConsole')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Database $dbForProject) {
|
||||
|
||||
$team = $dbForConsole->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -153,7 +152,7 @@ App::post('/v1/projects')
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
'format' => $attribute['format'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -184,15 +183,14 @@ App::get('/v1/projects')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT_LIST)
|
||||
->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Projects::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Projects::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForConsole) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -233,7 +231,6 @@ App::get('/v1/projects/:projectId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -260,7 +257,6 @@ App::get('/v1/projects/:projectId/usage')
|
||||
->inject('dbForProject')
|
||||
->inject('register')
|
||||
->action(function (string $projectId, string $range, Response $response, Database $dbForConsole, Database $dbForProject, Registry $register) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -298,7 +294,7 @@ App::get('/v1/projects/:projectId/usage')
|
||||
'databases.$all.count.total',
|
||||
'documents.$all.count.total',
|
||||
'executions.$all.compute.total',
|
||||
'buckets.$all.count.total'
|
||||
'buckets.$all.count.total',
|
||||
];
|
||||
|
||||
$stats = [];
|
||||
@@ -381,7 +377,6 @@ App::patch('/v1/projects/:projectId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $name, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -415,12 +410,11 @@ 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'), fn($element) => $element['optional'])), true), 'Service name.')
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])), true), 'Service name.')
|
||||
->param('status', null, new Boolean(), 'Service status.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $service, bool $status, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -453,7 +447,6 @@ App::patch('/v1/projects/:projectId/oauth2')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $provider, ?string $appId, ?string $secret, ?bool $enabled, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -463,15 +456,15 @@ App::patch('/v1/projects/:projectId/oauth2')
|
||||
$providers = $project->getAttribute('authProviders', []);
|
||||
|
||||
if ($appId !== null) {
|
||||
$providers[$provider . 'Appid'] = $appId;
|
||||
$providers[$provider.'Appid'] = $appId;
|
||||
}
|
||||
|
||||
if ($secret !== null) {
|
||||
$providers[$provider . 'Secret'] = $secret;
|
||||
$providers[$provider.'Secret'] = $secret;
|
||||
}
|
||||
|
||||
if ($enabled !== null) {
|
||||
$providers[$provider . 'Enabled'] = $enabled;
|
||||
$providers[$provider.'Enabled'] = $enabled;
|
||||
}
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('authProviders', $providers));
|
||||
@@ -494,7 +487,6 @@ App::patch('/v1/projects/:projectId/auth/limit')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -525,7 +517,6 @@ App::patch('/v1/projects/:projectId/auth/duration')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, int $duration, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -552,12 +543,11 @@ App::patch('/v1/projects/:projectId/auth/:method')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: ' . implode(',', \array_keys(Config::getParam('auth'))), false)
|
||||
->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: '.implode(',', \array_keys(Config::getParam('auth'))), false)
|
||||
->param('status', false, new Boolean(true), 'Set the status of this auth method.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $method, bool $status, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
$auth = Config::getParam('auth')[$method] ?? [];
|
||||
$authKey = $auth['key'] ?? '';
|
||||
@@ -586,11 +576,10 @@ App::patch('/v1/projects/:projectId/auth/max-sessions')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-' . APP_LIMIT_USER_SESSIONS_MAX . '. Default is ' . APP_LIMIT_USER_SESSIONS_DEFAULT)
|
||||
->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-'.APP_LIMIT_USER_SESSIONS_MAX.'. Default is '.APP_LIMIT_USER_SESSIONS_DEFAULT)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -622,8 +611,7 @@ App::delete('/v1/projects/:projectId')
|
||||
->inject('dbForConsole')
|
||||
->inject('deletes')
|
||||
->action(function (string $projectId, string $password, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
|
||||
|
||||
if (!Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password
|
||||
if (! Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password
|
||||
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
|
||||
}
|
||||
|
||||
@@ -635,10 +623,9 @@ App::delete('/v1/projects/:projectId')
|
||||
|
||||
$deletes
|
||||
->setType(DELETE_TYPE_DOCUMENT)
|
||||
->setDocument($project)
|
||||
;
|
||||
->setDocument($project);
|
||||
|
||||
if (!$dbForConsole->deleteDocument('projects', $projectId)) {
|
||||
if (! $dbForConsole->deleteDocument('projects', $projectId)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove project from DB');
|
||||
}
|
||||
|
||||
@@ -659,7 +646,7 @@ App::post('/v1/projects/:projectId/webhooks')
|
||||
->label('sdk.response.model', Response::MODEL_WEBHOOK)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.')
|
||||
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
|
||||
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
|
||||
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
|
||||
@@ -667,7 +654,6 @@ App::post('/v1/projects/:projectId/webhooks')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -717,7 +703,6 @@ App::get('/v1/projects/:projectId/webhooks')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -750,7 +735,6 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -782,7 +766,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.')
|
||||
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
|
||||
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
|
||||
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
|
||||
@@ -790,7 +774,6 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -814,8 +797,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->setAttribute('url', $url)
|
||||
->setAttribute('security', $security)
|
||||
->setAttribute('httpUser', $httpUser)
|
||||
->setAttribute('httpPass', $httpPass)
|
||||
;
|
||||
->setAttribute('httpPass', $httpPass);
|
||||
|
||||
$dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
@@ -838,7 +820,6 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -876,7 +857,6 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -913,12 +893,11 @@ App::post('/v1/projects/:projectId/keys')
|
||||
->label('sdk.response.model', Response::MODEL_KEY)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' scopes are allowed.')
|
||||
->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -965,7 +944,6 @@ App::get('/v1/projects/:projectId/keys')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -998,7 +976,6 @@ App::get('/v1/projects/:projectId/keys/:keyId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1030,12 +1007,11 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('keyId', '', new UID(), 'Key unique ID.')
|
||||
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.')
|
||||
->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $keyId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1054,8 +1030,7 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
||||
$key
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('scopes', $scopes)
|
||||
->setAttribute('expire', $expire)
|
||||
;
|
||||
->setAttribute('expire', $expire);
|
||||
|
||||
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
||||
|
||||
@@ -1078,7 +1053,6 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1141,7 +1115,7 @@ App::post('/v1/projects/:projectId/platforms')
|
||||
'name' => $name,
|
||||
'key' => $key,
|
||||
'store' => $store,
|
||||
'hostname' => $hostname
|
||||
'hostname' => $hostname,
|
||||
]);
|
||||
|
||||
$platform = $dbForConsole->createDocument('platforms', $platform);
|
||||
@@ -1167,7 +1141,6 @@ App::get('/v1/projects/:projectId/platforms')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1200,7 +1173,6 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1257,8 +1229,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('key', $key)
|
||||
->setAttribute('store', $store)
|
||||
->setAttribute('hostname', $hostname)
|
||||
;
|
||||
->setAttribute('hostname', $hostname);
|
||||
|
||||
$dbForConsole->updateDocument('platforms', $platform->getId(), $platform);
|
||||
|
||||
@@ -1281,7 +1252,6 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1321,7 +1291,6 @@ App::post('/v1/projects/:projectId/domains')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domain, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1333,14 +1302,14 @@ App::post('/v1/projects/:projectId/domains')
|
||||
Query::equal('projectInternalId', [$project->getInternalId()]),
|
||||
]);
|
||||
|
||||
if ($document && !$document->isEmpty()) {
|
||||
if ($document && ! $document->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
if (!$target->isKnown() || $target->isTest()) {
|
||||
throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target (' . $target->get() . '). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.');
|
||||
if (! $target->isKnown() || $target->isTest()) {
|
||||
throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target ('.$target->get().'). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.');
|
||||
}
|
||||
|
||||
$domain = new Domain($domain);
|
||||
@@ -1385,7 +1354,6 @@ App::get('/v1/projects/:projectId/domains')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1418,7 +1386,6 @@ App::get('/v1/projects/:projectId/domains/:domainId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1452,7 +1419,6 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1470,8 +1436,8 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
|
||||
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
if (!$target->isKnown() || $target->isTest()) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.');
|
||||
if (! $target->isKnown() || $target->isTest()) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.');
|
||||
}
|
||||
|
||||
if ($domain->getAttribute('verification') === true) {
|
||||
@@ -1480,11 +1446,10 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
|
||||
|
||||
$validator = new CNAME($target->get()); // Verify Domain with DNS records
|
||||
|
||||
if (!$validator->isValid($domain->getAttribute('domain', ''))) {
|
||||
if (! $validator->isValid($domain->getAttribute('domain', ''))) {
|
||||
throw new Exception(Exception::DOMAIN_VERIFICATION_FAILED);
|
||||
}
|
||||
|
||||
|
||||
$dbForConsole->updateDocument('domains', $domain->getId(), $domain->setAttribute('verification', true));
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
||||
@@ -1512,7 +1477,6 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
|
||||
->inject('dbForConsole')
|
||||
->inject('deletes')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole, Delete $deletes) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
|
||||
+139
-164
@@ -4,28 +4,28 @@ use Appwrite\Auth\Auth;
|
||||
use Appwrite\ClamAV\Network;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Buckets;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Files;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Authorization as AuthorizationException;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Buckets;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Files;
|
||||
use Utopia\Image\Image;
|
||||
use Utopia\Storage\Compression\Algorithms\GZIP;
|
||||
use Utopia\Storage\Compression\Algorithms\Zstd;
|
||||
@@ -35,13 +35,13 @@ use Utopia\Storage\Validator\File;
|
||||
use Utopia\Storage\Validator\FileExt;
|
||||
use Utopia\Storage\Validator\FileSize;
|
||||
use Utopia\Storage\Validator\Upload;
|
||||
use Utopia\Swoole\Request;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\HexColor;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Swoole\Request;
|
||||
|
||||
App::post('/v1/storage/buckets')
|
||||
->desc('Create bucket')
|
||||
@@ -63,16 +63,15 @@ App::post('/v1/storage/buckets')
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
|
||||
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
|
||||
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is '.Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0).'. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' extensions are allowed, each 64 characters long.', true)
|
||||
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd), For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' compression is skipped even if it\'s enabled', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above '.Storage::human(APP_LIMIT_ANTIVIRUS, 0).' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$bucketId = $bucketId === 'unique()' ? ID::unique() : $bucketId;
|
||||
|
||||
// Map aggregate permissions into the multiple permissions they represent.
|
||||
@@ -97,7 +96,7 @@ App::post('/v1/storage/buckets')
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
'format' => $attribute['format'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -128,14 +127,13 @@ App::post('/v1/storage/buckets')
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
|
||||
$dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
|
||||
$dbForProject->createCollection('bucket_'.$bucket->getInternalId(), $attributes, $indexes);
|
||||
} catch (Duplicate) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
;
|
||||
->setParam('bucketId', $bucket->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -154,15 +152,14 @@ App::get('/v1/storage/buckets')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_BUCKET_LIST)
|
||||
->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Buckets::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Buckets::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -205,7 +202,6 @@ App::get('/v1/storage/buckets/:bucketId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $bucketId, Response $response, Database $dbForProject) {
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
|
||||
if ($bucket->isEmpty()) {
|
||||
@@ -235,11 +231,11 @@ App::put('/v1/storage/buckets/:bucketId')
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
|
||||
->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
|
||||
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is '.Storage::human((int) App::getEnv('_APP_STORAGE_LIMIT', 0), 0).'. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' extensions are allowed, each 64 characters long.', true)
|
||||
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd), For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' compression is skipped even if it\'s enabled', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above '.Storage::human(APP_LIMIT_ANTIVIRUS, 0).' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
@@ -276,8 +272,7 @@ App::put('/v1/storage/buckets/:bucketId')
|
||||
->setAttribute('antivirus', $antivirus));
|
||||
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
;
|
||||
->setParam('bucketId', $bucket->getId());
|
||||
|
||||
$response->dynamic($bucket, Response::MODEL_BUCKET);
|
||||
});
|
||||
@@ -308,7 +303,7 @@ App::delete('/v1/storage/buckets/:bucketId')
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteDocument('buckets', $bucketId)) {
|
||||
if (! $dbForProject->deleteDocument('buckets', $bucketId)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove bucket from DB');
|
||||
}
|
||||
|
||||
@@ -318,8 +313,7 @@ App::delete('/v1/storage/buckets/:bucketId')
|
||||
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
->setPayload($response->output($bucket, Response::MODEL_BUCKET))
|
||||
;
|
||||
->setPayload($response->output($bucket, Response::MODEL_BUCKET));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -360,15 +354,14 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
->inject('deviceLocal')
|
||||
->inject('deletes')
|
||||
->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal, Delete $deletes) {
|
||||
|
||||
$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(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$validator = new Authorization(Database::PERMISSION_CREATE);
|
||||
if (!$validator->isValid($bucket->getCreate())) {
|
||||
if (! $validator->isValid($bucket->getCreate())) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@@ -384,7 +377,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
// Add permissions for current the user if none were provided.
|
||||
if (\is_null($permissions)) {
|
||||
$permissions = [];
|
||||
if (!empty($user->getId())) {
|
||||
if (! empty($user->getId())) {
|
||||
foreach ($allowedPermissions as $permission) {
|
||||
$permissions[] = (new Permission($permission, 'user', $user->getId()))->toString();
|
||||
}
|
||||
@@ -393,7 +386,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
$roles = Authorization::getRoles();
|
||||
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) {
|
||||
if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles)) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
@@ -405,8 +398,8 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$permission->getIdentifier(),
|
||||
$permission->getDimension()
|
||||
))->toString();
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')');
|
||||
if (! Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -417,7 +410,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Maximum bucket file size is larger than _APP_STORAGE_LIMIT');
|
||||
}
|
||||
|
||||
|
||||
$file = $request->getFiles('file');
|
||||
|
||||
// GraphQL multipart spec adds files with index keys
|
||||
@@ -439,7 +431,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$chunk = 1;
|
||||
$chunks = 1;
|
||||
|
||||
if (!empty($contentRange)) {
|
||||
if (! empty($contentRange)) {
|
||||
$start = $request->getContentRangeStart();
|
||||
$end = $request->getContentRangeEnd();
|
||||
$fileSize = $request->getContentRangeSize();
|
||||
@@ -464,30 +456,30 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
// Check if file type is allowed
|
||||
$allowedFileExtensions = $bucket->getAttribute('allowedFileExtensions', []);
|
||||
$fileExt = new FileExt($allowedFileExtensions);
|
||||
if (!empty($allowedFileExtensions) && !$fileExt->isValid($fileName)) {
|
||||
if (! empty($allowedFileExtensions) && ! $fileExt->isValid($fileName)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED, 'File extension not allowed');
|
||||
}
|
||||
|
||||
// Check if file size is exceeding allowed limit
|
||||
$fileSizeValidator = new FileSize($maximumFileSize);
|
||||
if (!$fileSizeValidator->isValid($fileSize)) {
|
||||
if (! $fileSizeValidator->isValid($fileSize)) {
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE, 'File size not allowed');
|
||||
}
|
||||
|
||||
$upload = new Upload();
|
||||
if (!$upload->isValid($fileTmpName)) {
|
||||
if (! $upload->isValid($fileTmpName)) {
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE);
|
||||
}
|
||||
|
||||
// Save to storage
|
||||
$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
|
||||
$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
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
|
||||
$metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)];
|
||||
if (!$file->isEmpty()) {
|
||||
if (! $file->isEmpty()) {
|
||||
$chunks = $file->getAttribute('chunksTotal', 1);
|
||||
$metadata = $file->getAttribute('metadata', []);
|
||||
if ($chunk === -1) {
|
||||
@@ -507,7 +499,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310)
|
||||
);
|
||||
|
||||
if (!$antivirus->fileScan($path)) {
|
||||
if (! $antivirus->fileScan($path)) {
|
||||
$deviceFiles->delete($path);
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE);
|
||||
}
|
||||
@@ -540,8 +532,8 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
if (!$deviceFiles->write($path, $data, $mimeType)) {
|
||||
if (! empty($data)) {
|
||||
if (! $deviceFiles->write($path, $data, $mimeType)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to save file');
|
||||
}
|
||||
}
|
||||
@@ -585,7 +577,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
'metadata' => $metadata,
|
||||
]);
|
||||
|
||||
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
|
||||
$file = $dbForProject->createDocument('bucket_'.$bucket->getInternalId(), $doc);
|
||||
} else {
|
||||
$file = $file
|
||||
->setAttribute('$permissions', $permissions)
|
||||
@@ -600,7 +592,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
->setAttribute('metadata', $metadata)
|
||||
->setAttribute('chunksUploaded', $chunksUploaded);
|
||||
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
|
||||
$file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file);
|
||||
}
|
||||
} catch (AuthorizationException) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
@@ -630,13 +622,13 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
'metadata' => $metadata,
|
||||
]);
|
||||
|
||||
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
|
||||
$file = $dbForProject->createDocument('bucket_'.$bucket->getInternalId(), $doc);
|
||||
} else {
|
||||
$file = $file
|
||||
->setAttribute('chunksUploaded', $chunksUploaded)
|
||||
->setAttribute('metadata', $metadata);
|
||||
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
|
||||
$file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file);
|
||||
}
|
||||
} catch (AuthorizationException) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
@@ -650,13 +642,11 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
->setParam('fileId', $file->getId())
|
||||
->setContext('bucket', $bucket)
|
||||
;
|
||||
->setContext('bucket', $bucket);
|
||||
|
||||
$deletes
|
||||
->setType(DELETE_TYPE_CACHE_BY_RESOURCE)
|
||||
->setResource('file/' . $file->getId())
|
||||
;
|
||||
->setResource('file/'.$file->getId());
|
||||
|
||||
$metadata = null; // was causing leaks as it was passed by reference
|
||||
|
||||
@@ -680,29 +670,28 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FILE_LIST)
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Files::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$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(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -713,10 +702,10 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
/** @var Query $cursor */
|
||||
$fileId = $cursor->getValue();
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$cursorDocument = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$cursorDocument = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($cursorDocument->isEmpty()) {
|
||||
@@ -728,12 +717,12 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$files = $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries);
|
||||
$total = $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$files = $dbForProject->find('bucket_'.$bucket->getInternalId(), $queries);
|
||||
$total = $dbForProject->count('bucket_'.$bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT);
|
||||
} else {
|
||||
$files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries));
|
||||
$total = Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT));
|
||||
$files = Authorization::skip(fn () => $dbForProject->find('bucket_'.$bucket->getInternalId(), $queries));
|
||||
$total = Authorization::skip(fn () => $dbForProject->count('bucket_'.$bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT));
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
@@ -762,24 +751,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$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(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -810,7 +798,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
->param('fileId', '', new UID(), 'File ID')
|
||||
->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true)
|
||||
->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true)
|
||||
->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of ' . implode(",", Image::getGravityTypes()), true)
|
||||
->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of '.implode(',', Image::getGravityTypes()), true)
|
||||
->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
|
||||
->param('borderWidth', 0, new Range(0, 100), 'Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.', true)
|
||||
->param('borderColor', '', new HexColor(), 'Preview image border color. Use a valid HEX color, no # is needed for prefix.', true)
|
||||
@@ -827,21 +815,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
->inject('deviceFiles')
|
||||
->inject('deviceLocal')
|
||||
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Request $request, Response $response, Document $project, Database $dbForProject, string $mode, Device $deviceFiles, Device $deviceLocal) {
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
if (! \extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
$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(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@@ -853,10 +840,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$outputs = Config::getParam('storage-outputs');
|
||||
$fileLogos = Config::getParam('storage-logos');
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -868,8 +855,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$algorithm = $file->getAttribute('algorithm', 'none');
|
||||
$cipher = $file->getAttribute('openSSLCipher');
|
||||
$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) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) {
|
||||
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
|
||||
@@ -883,7 +870,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$deviceFiles = $deviceLocal;
|
||||
}
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
if (! $deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -893,14 +880,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type;
|
||||
}
|
||||
|
||||
|
||||
$source = $deviceFiles->read($path);
|
||||
|
||||
if (!empty($cipher)) { // Decrypt
|
||||
if (! empty($cipher)) { // Decrypt
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
@@ -922,23 +908,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
|
||||
$image->crop((int) $width, (int) $height, $gravity);
|
||||
|
||||
if (!empty($opacity) || $opacity === 0) {
|
||||
if (! empty($opacity) || $opacity === 0) {
|
||||
$image->setOpacity($opacity);
|
||||
}
|
||||
|
||||
if (!empty($background)) {
|
||||
$image->setBackground('#' . $background);
|
||||
if (! empty($background)) {
|
||||
$image->setBackground('#'.$background);
|
||||
}
|
||||
|
||||
if (!empty($borderWidth)) {
|
||||
$image->setBorder($borderWidth, '#' . $borderColor);
|
||||
if (! empty($borderWidth)) {
|
||||
$image->setBorder($borderWidth, '#'.$borderColor);
|
||||
}
|
||||
|
||||
if (!empty($borderRadius)) {
|
||||
if (! empty($borderRadius)) {
|
||||
$image->setBorderRadius($borderRadius);
|
||||
}
|
||||
|
||||
if (!empty($rotation)) {
|
||||
if (! empty($rotation)) {
|
||||
$image->setRotation(($rotation + 360) % 360);
|
||||
}
|
||||
|
||||
@@ -947,10 +933,9 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg'];
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType($contentType)
|
||||
->file($data)
|
||||
;
|
||||
->file($data);
|
||||
|
||||
unset($image);
|
||||
});
|
||||
@@ -977,24 +962,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
->inject('mode')
|
||||
->inject('deviceFiles')
|
||||
->action(function (string $bucketId, string $fileId, Request $request, Response $response, Database $dbForProject, string $mode, Device $deviceFiles) {
|
||||
|
||||
$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(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -1003,21 +987,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
|
||||
$path = $file->getAttribute('path', '');
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
|
||||
if (! $deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in '.$path);
|
||||
}
|
||||
|
||||
$response
|
||||
->setContentType($file->getAttribute('mimeType'))
|
||||
->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())
|
||||
->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"')
|
||||
;
|
||||
->addHeader('Content-Disposition', 'attachment; filename="'.$file->getAttribute('name', '').'"');
|
||||
|
||||
$size = $file->getAttribute('sizeOriginal', 0);
|
||||
|
||||
$rangeHeader = $request->getHeader('range');
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$start = $request->getRangeStart();
|
||||
$end = $request->getRangeEnd();
|
||||
$unit = $request->getRangeUnit();
|
||||
@@ -1032,18 +1015,18 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
|
||||
$response
|
||||
->addHeader('Accept-Ranges', 'bytes')
|
||||
->addHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $size)
|
||||
->addHeader('Content-Range', 'bytes '.$start.'-'.$end.'/'.$size)
|
||||
->addHeader('Content-Length', $end - $start + 1)
|
||||
->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT);
|
||||
}
|
||||
|
||||
$source = '';
|
||||
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
if (! empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
@@ -1067,14 +1050,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($source)) {
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($source)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$response->send(substr($source, $start, ($end - $start + 1)));
|
||||
}
|
||||
$response->send($source);
|
||||
}
|
||||
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$response->send($deviceFiles->read($path, $start, ($end - $start + 1)));
|
||||
}
|
||||
|
||||
@@ -1117,24 +1100,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
->inject('mode')
|
||||
->inject('deviceFiles')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Request $request, Database $dbForProject, string $mode, Device $deviceFiles) {
|
||||
|
||||
$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(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -1145,8 +1127,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
|
||||
$path = $file->getAttribute('path', '');
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
|
||||
if (! $deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in '.$path);
|
||||
}
|
||||
|
||||
$contentType = 'text/plain';
|
||||
@@ -1159,15 +1141,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
->setContentType($contentType)
|
||||
->addHeader('Content-Security-Policy', 'script-src none;')
|
||||
->addHeader('X-Content-Type-Options', 'nosniff')
|
||||
->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"')
|
||||
->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())
|
||||
;
|
||||
->addHeader('Content-Disposition', 'inline; filename="'.$file->getAttribute('name', '').'"')
|
||||
->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());
|
||||
|
||||
$size = $file->getAttribute('sizeOriginal', 0);
|
||||
|
||||
$rangeHeader = $request->getHeader('range');
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$start = $request->getRangeStart();
|
||||
$end = $request->getRangeEnd();
|
||||
$unit = $request->getRangeUnit();
|
||||
@@ -1188,12 +1169,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
}
|
||||
|
||||
$source = '';
|
||||
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
if (! empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
@@ -1217,14 +1198,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($source)) {
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($source)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$response->send(substr($source, $start, ($end - $start + 1)));
|
||||
}
|
||||
$response->send($source);
|
||||
}
|
||||
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$response->send($deviceFiles->read($path, $start, ($end - $start + 1)));
|
||||
}
|
||||
|
||||
@@ -1275,22 +1256,21 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
->inject('mode')
|
||||
->inject('events')
|
||||
->action(function (string $bucketId, string $fileId, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $events) {
|
||||
|
||||
$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(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttributes('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_UPDATE);
|
||||
$valid = $validator->isValid($bucket->getUpdate());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
// Read permission should not be required for update
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
@@ -1305,7 +1285,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
$roles = Authorization::getRoles();
|
||||
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) {
|
||||
if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles) && ! \is_null($permissions)) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
@@ -1317,8 +1297,8 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
$permission->getIdentifier(),
|
||||
$permission->getDimension()
|
||||
))->toString();
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')');
|
||||
if (! Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1330,21 +1310,20 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
|
||||
$file->setAttribute('$permissions', $permissions);
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
if ($fileSecurity && ! $valid) {
|
||||
try {
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
|
||||
$file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file);
|
||||
} catch (AuthorizationException) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file));
|
||||
$file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file));
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
->setParam('fileId', $file->getId())
|
||||
->setContext('bucket', $bucket)
|
||||
;
|
||||
->setContext('bucket', $bucket);
|
||||
|
||||
$response->dynamic($file, Response::MODEL_FILE);
|
||||
});
|
||||
@@ -1379,26 +1358,26 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, string $mode, Device $deviceFiles, Delete $deletes) {
|
||||
$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(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttributes('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_DELETE);
|
||||
$valid = $validator->isValid($bucket->getDelete());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
// Read permission should not be required for delete
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Make sure we don't delete the file before the document permission check occurs
|
||||
if ($fileSecurity && !$valid && !$validator->isValid($file->getDelete())) {
|
||||
if ($fileSecurity && ! $valid && ! $validator->isValid($file->getDelete())) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@@ -1415,20 +1394,19 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
if ($deviceDeleted) {
|
||||
$deletes
|
||||
->setType(DELETE_TYPE_CACHE_BY_RESOURCE)
|
||||
->setResource('file/' . $fileId)
|
||||
;
|
||||
->setResource('file/'.$fileId);
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
if ($fileSecurity && ! $valid) {
|
||||
try {
|
||||
$deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
$deleted = $dbForProject->deleteDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} catch (AuthorizationException) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
} else {
|
||||
$deleted = Authorization::skip(fn() => $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if (!$deleted) {
|
||||
if (! $deleted) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove file from DB');
|
||||
}
|
||||
} else {
|
||||
@@ -1439,8 +1417,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
->setParam('fileId', $file->getId())
|
||||
->setContext('bucket', $bucket)
|
||||
->setPayload($response->output($file, Response::MODEL_FILE))
|
||||
;
|
||||
->setPayload($response->output($file, Response::MODEL_FILE));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -1459,7 +1436,6 @@ App::get('/v1/storage/usage')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$usage = [];
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') === 'enabled') {
|
||||
$periods = [
|
||||
@@ -1570,7 +1546,6 @@ App::get('/v1/storage/:bucketId/usage')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $bucketId, string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
|
||||
if ($bucket->isEmpty()) {
|
||||
|
||||
@@ -7,7 +7,6 @@ use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Utopia\Validator\Host;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries;
|
||||
@@ -23,22 +22,21 @@ use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Authorization as AuthorizationException;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Validator\Host;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
App::post('/v1/teams')
|
||||
->desc('Create Team')
|
||||
@@ -56,18 +54,17 @@ App::post('/v1/teams')
|
||||
->label('sdk.response.model', Response::MODEL_TEAM)
|
||||
->param('teamId', '', new CustomId(), 'Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. 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('name', null, new Text(128), 'Team name. Max length: 128 chars.')
|
||||
->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. 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.', true)
|
||||
->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. 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.', true)
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $events) {
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
$isAppUser = Auth::isAppUser(Authorization::getRoles());
|
||||
|
||||
$teamId = $teamId == 'unique()' ? ID::unique() : $teamId;
|
||||
$team = Authorization::skip(fn() => $dbForProject->createDocument('teams', new Document([
|
||||
$team = Authorization::skip(fn () => $dbForProject->createDocument('teams', new Document([
|
||||
'$id' => $teamId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::team($teamId)),
|
||||
@@ -79,8 +76,8 @@ App::post('/v1/teams')
|
||||
'search' => implode(' ', [$teamId, $name]),
|
||||
])));
|
||||
|
||||
if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode
|
||||
if (!\in_array('owner', $roles)) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser) { // Don't add user on server mode
|
||||
if (! \in_array('owner', $roles)) {
|
||||
$roles[] = 'owner';
|
||||
}
|
||||
|
||||
@@ -104,7 +101,7 @@ App::post('/v1/teams')
|
||||
'joined' => DateTime::now(),
|
||||
'confirm' => true,
|
||||
'secret' => '',
|
||||
'search' => implode(' ', [$membershipId, $user->getId()])
|
||||
'search' => implode(' ', [$membershipId, $user->getId()]),
|
||||
]);
|
||||
|
||||
$membership = $dbForProject->createDocument('memberships', $membership);
|
||||
@@ -113,7 +110,7 @@ App::post('/v1/teams')
|
||||
|
||||
$events->setParam('teamId', $team->getId());
|
||||
|
||||
if (!empty($user->getId())) {
|
||||
if (! empty($user->getId())) {
|
||||
$events->setParam('userId', $user->getId());
|
||||
}
|
||||
|
||||
@@ -134,15 +131,14 @@ App::get('/v1/teams')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TEAM_LIST)
|
||||
->label('sdk.offline.model', '/teams')
|
||||
->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Teams::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -189,7 +185,6 @@ App::get('/v1/teams/:teamId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, Response $response, Database $dbForProject) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -221,7 +216,6 @@ App::put('/v1/teams/:teamId')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $name, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -256,7 +250,6 @@ App::delete('/v1/teams/:teamId')
|
||||
->inject('events')
|
||||
->inject('deletes')
|
||||
->action(function (string $teamId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -270,12 +263,12 @@ App::delete('/v1/teams/:teamId')
|
||||
|
||||
// TODO delete all members individually from the user object
|
||||
foreach ($memberships as $membership) {
|
||||
if (!$dbForProject->deleteDocument('memberships', $membership->getId())) {
|
||||
if (! $dbForProject->deleteDocument('memberships', $membership->getId())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove membership for team from DB');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteDocument('teams', $teamId)) {
|
||||
if (! $dbForProject->deleteDocument('teams', $teamId)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove team from DB');
|
||||
}
|
||||
|
||||
@@ -285,8 +278,7 @@ App::delete('/v1/teams/:teamId')
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
->setPayload($response->output($team, Response::MODEL_TEAM))
|
||||
;
|
||||
->setPayload($response->output($team, Response::MODEL_TEAM));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -310,8 +302,8 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->label('abuse-limit', 10)
|
||||
->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', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
|
||||
->param('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', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
|
||||
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
@@ -321,11 +313,10 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->inject('mails')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $email, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, Event $events) {
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
$isAppUser = Auth::isAppUser(Authorization::getRoles());
|
||||
|
||||
if (!$isPrivilegedUser && !$isAppUser && empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser && empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception(Exception::GENERAL_SMTP_DISABLED);
|
||||
}
|
||||
|
||||
@@ -352,7 +343,7 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
|
||||
try {
|
||||
$userId = ID::unique();
|
||||
$invitee = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([
|
||||
$invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([
|
||||
'$id' => $userId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
@@ -379,16 +370,16 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name])
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
])));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
$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)
|
||||
if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server)
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to send invitations for this team');
|
||||
}
|
||||
|
||||
@@ -413,17 +404,17 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
'joined' => ($isPrivilegedUser || $isAppUser) ? DateTime::now() : null,
|
||||
'confirm' => ($isPrivilegedUser || $isAppUser),
|
||||
'secret' => Auth::hash($secret),
|
||||
'search' => implode(' ', [$membershipId, $invitee->getId()])
|
||||
'search' => implode(' ', [$membershipId, $invitee->getId()]),
|
||||
]);
|
||||
|
||||
if ($isPrivilegedUser || $isAppUser) { // Allow admin to create membership
|
||||
try {
|
||||
$membership = Authorization::skip(fn() => $dbForProject->createDocument('memberships', $membership));
|
||||
$membership = Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::TEAM_INVITE_ALREADY_EXISTS);
|
||||
}
|
||||
$team->setAttribute('total', $team->getAttribute('total', 0) + 1);
|
||||
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
$team = Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $invitee->getId());
|
||||
} else {
|
||||
@@ -438,24 +429,24 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]);
|
||||
$url = Template::unParseURL($url);
|
||||
|
||||
if (!$isPrivilegedUser && !$isAppUser) { // No need of confirmation when in admin or app mode
|
||||
if (! $isPrivilegedUser && ! $isAppUser) { // No need of confirmation when in admin or app mode
|
||||
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
|
||||
|
||||
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
|
||||
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
|
||||
$subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName);
|
||||
$body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl');
|
||||
$subject = \sprintf($locale->getText('emails.invitation.subject'), $team->getAttribute('name'), $projectName);
|
||||
$body->setParam('{{owner}}', $user->getAttribute('name'));
|
||||
$body->setParam('{{team}}', $team->getAttribute('name'));
|
||||
|
||||
$body
|
||||
->setParam('{{subject}}', $subject)
|
||||
->setParam('{{hello}}', $locale->getText("emails.invitation.hello"))
|
||||
->setParam('{{hello}}', $locale->getText('emails.invitation.hello'))
|
||||
->setParam('{{name}}', $user->getAttribute('name'))
|
||||
->setParam('{{body}}', $locale->getText("emails.invitation.body"))
|
||||
->setParam('{{body}}', $locale->getText('emails.invitation.body'))
|
||||
->setParam('{{redirect}}', $url)
|
||||
->setParam('{{footer}}', $locale->getText("emails.invitation.footer"))
|
||||
->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks"))
|
||||
->setParam('{{signature}}', $locale->getText("emails.invitation.signature"))
|
||||
->setParam('{{footer}}', $locale->getText('emails.invitation.footer'))
|
||||
->setParam('{{thanks}}', $locale->getText('emails.invitation.thanks'))
|
||||
->setParam('{{signature}}', $locale->getText('emails.invitation.signature'))
|
||||
->setParam('{{project}}', $projectName)
|
||||
->setParam('{{direction}}', $locale->getText('settings.direction'))
|
||||
->setParam('{{bg-body}}', '#f7f7f7')
|
||||
@@ -470,14 +461,12 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->setFrom($from)
|
||||
->setRecipient($invitee->getAttribute('email'))
|
||||
->setName($invitee->getAttribute('name'))
|
||||
->trigger()
|
||||
;
|
||||
->trigger();
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
->setParam('membershipId', $membership->getId())
|
||||
;
|
||||
->setParam('membershipId', $membership->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -503,12 +492,11 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST)
|
||||
->label('sdk.offline.model', '/teams/{teamId}/memberships')
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -517,7 +505,7 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -552,7 +540,7 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
max: APP_LIMIT_COUNT
|
||||
);
|
||||
|
||||
$memberships = array_filter($memberships, fn(Document $membership) => !empty($membership->getAttribute('userId')));
|
||||
$memberships = array_filter($memberships, fn (Document $membership) => ! empty($membership->getAttribute('userId')));
|
||||
|
||||
$memberships = array_map(function ($membership) use ($dbForProject, $team) {
|
||||
$user = $dbForProject->getDocument('users', $membership->getAttribute('userId'));
|
||||
@@ -560,8 +548,7 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
$membership
|
||||
->setAttribute('teamName', $team->getAttribute('name'))
|
||||
->setAttribute('userName', $user->getAttribute('name'))
|
||||
->setAttribute('userEmail', $user->getAttribute('email'))
|
||||
;
|
||||
->setAttribute('userEmail', $user->getAttribute('email'));
|
||||
|
||||
return $membership;
|
||||
}, $memberships);
|
||||
@@ -590,7 +577,6 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -608,8 +594,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
||||
$membership
|
||||
->setAttribute('teamName', $team->getAttribute('name'))
|
||||
->setAttribute('userName', $user->getAttribute('name'))
|
||||
->setAttribute('userEmail', $user->getAttribute('email'))
|
||||
;
|
||||
->setAttribute('userEmail', $user->getAttribute('email'));
|
||||
|
||||
$response->dynamic($membership, Response::MODEL_MEMBERSHIP);
|
||||
});
|
||||
@@ -630,14 +615,13 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->label('sdk.response.model', Response::MODEL_MEMBERSHIP)
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('membershipId', '', new UID(), 'Membership ID.')
|
||||
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
|
||||
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
if ($team->isEmpty()) {
|
||||
throw new Exception(Exception::TEAM_NOT_FOUND);
|
||||
@@ -655,9 +639,9 @@ 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)
|
||||
if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server)
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to modify roles');
|
||||
}
|
||||
|
||||
@@ -724,7 +708,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
throw new Exception(Exception::TEAM_MEMBERSHIP_MISMATCH);
|
||||
}
|
||||
|
||||
$team = Authorization::skip(fn() => $dbForProject->getDocument('teams', $teamId));
|
||||
$team = Authorization::skip(fn () => $dbForProject->getDocument('teams', $teamId));
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
throw new Exception(Exception::TEAM_NOT_FOUND);
|
||||
@@ -735,7 +719,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
}
|
||||
|
||||
if ($userId !== $membership->getAttribute('userId')) {
|
||||
throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')');
|
||||
throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')');
|
||||
}
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -743,7 +727,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
}
|
||||
|
||||
if ($membership->getAttribute('userId') !== $user->getId()) {
|
||||
throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')');
|
||||
throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')');
|
||||
}
|
||||
|
||||
if ($membership->getAttribute('confirm') === true) {
|
||||
@@ -752,10 +736,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
|
||||
$membership // Attach user to team
|
||||
->setAttribute('joined', DateTime::now())
|
||||
->setAttribute('confirm', true)
|
||||
;
|
||||
->setAttribute('confirm', true);
|
||||
|
||||
$user = Authorization::skip(fn() => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true)));
|
||||
$user = Authorization::skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true)));
|
||||
|
||||
// Log user in
|
||||
|
||||
@@ -793,23 +776,20 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
|
||||
$team = Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
->setParam('membershipId', $membership->getId())
|
||||
;
|
||||
->setParam('membershipId', $membership->getId());
|
||||
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
if (! Config::getParam('domainVerification')) {
|
||||
$response
|
||||
->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]))
|
||||
;
|
||||
->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]));
|
||||
}
|
||||
|
||||
$response
|
||||
->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
;
|
||||
->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'));
|
||||
|
||||
$response->dynamic(
|
||||
$membership
|
||||
@@ -839,7 +819,6 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$membership = $dbForProject->getDocument('memberships', $membershipId);
|
||||
|
||||
if ($membership->isEmpty()) {
|
||||
@@ -874,14 +853,13 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
|
||||
if ($membership->getAttribute('confirm')) { // Count only confirmed members
|
||||
$team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0));
|
||||
Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
->setParam('membershipId', $membership->getId())
|
||||
->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP))
|
||||
;
|
||||
->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -904,7 +882,6 @@ App::get('/v1/teams/:teamId/logs')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $teamId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -917,13 +894,13 @@ App::get('/v1/teams/:teamId/logs')
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'team/' . $team->getId();
|
||||
$resource = 'team/'.$team->getId();
|
||||
$logs = $audit->getLogsByResource($resource, $limit, $offset);
|
||||
|
||||
$output = [];
|
||||
|
||||
foreach ($logs as $i => &$log) {
|
||||
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
$log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
|
||||
$detector = new Detector($log['userAgent']);
|
||||
$detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
|
||||
@@ -951,14 +928,14 @@ App::get('/v1/teams/:teamId/logs')
|
||||
'clientEngineVersion' => $client['clientEngineVersion'],
|
||||
'deviceName' => $device['deviceName'],
|
||||
'deviceBrand' => $device['deviceBrand'],
|
||||
'deviceModel' => $device['deviceModel']
|
||||
'deviceModel' => $device['deviceModel'],
|
||||
]);
|
||||
|
||||
$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');
|
||||
|
||||
@@ -6,6 +6,7 @@ use Appwrite\Auth\Validator\Phone;
|
||||
use Appwrite\Detector\Detector;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries;
|
||||
@@ -13,34 +14,33 @@ use Appwrite\Utopia\Database\Validator\Queries\Users;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Limit;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Offset;
|
||||
use Appwrite\Utopia\Response;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Locale\Locale;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\Boolean;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
/** TODO: Remove function when we move to using utopia/platform */
|
||||
function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Database $dbForProject, Event $events): Document
|
||||
{
|
||||
$hashOptionsObject = (\is_string($hashOptions)) ? \json_decode($hashOptions, true) : $hashOptions; // Cast to JSON array
|
||||
|
||||
if (!empty($email)) {
|
||||
if (! empty($email)) {
|
||||
$email = \strtolower($email);
|
||||
}
|
||||
|
||||
@@ -61,10 +61,10 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||
'phone' => $phone,
|
||||
'phoneVerification' => false,
|
||||
'status' => true,
|
||||
'password' => (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null,
|
||||
'password' => (! empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null,
|
||||
'hash' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO : $hash,
|
||||
'hashOptions' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO_OPTIONS : $hashOptionsObject + ['type' => $hash],
|
||||
'passwordUpdate' => (!empty($password)) ? DateTime::now() : null,
|
||||
'passwordUpdate' => (! empty($password)) ? DateTime::now() : null,
|
||||
'registration' => DateTime::now(),
|
||||
'reset' => false,
|
||||
'name' => $name,
|
||||
@@ -72,7 +72,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $phone, $name])
|
||||
'search' => implode(' ', [$userId, $email, $phone, $name]),
|
||||
]));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
@@ -230,8 +230,8 @@ App::post('/v1/users/sha')
|
||||
->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Database $dbForProject, Event $events) {
|
||||
$options = '{}';
|
||||
|
||||
if (!empty($passwordVersion)) {
|
||||
$options = '{"version":"' . $passwordVersion . '"}';
|
||||
if (! empty($passwordVersion)) {
|
||||
$options = '{"version":"'.$passwordVersion.'"}';
|
||||
}
|
||||
|
||||
$user = createUser('sha', $options, $userId, $email, $password, null, $name, $dbForProject, $events);
|
||||
@@ -304,7 +304,7 @@ App::post('/v1/users/scrypt')
|
||||
'costCpu' => $passwordCpu,
|
||||
'costMemory' => $passwordMemory,
|
||||
'costParallel' => $passwordParallel,
|
||||
'length' => $passwordLength
|
||||
'length' => $passwordLength,
|
||||
];
|
||||
|
||||
$user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $dbForProject, $events);
|
||||
@@ -340,7 +340,7 @@ App::post('/v1/users/scrypt-modified')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Database $dbForProject, Event $events) {
|
||||
$user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $dbForProject, $events);
|
||||
$user = createUser('scryptMod', '{"signerKey":"'.$passwordSignerKey.'","saltSeparator":"'.$passwordSaltSeparator.'","salt":"'.$passwordSalt.'"}', $userId, $email, $password, null, $name, $dbForProject, $events);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -359,15 +359,14 @@ App::get('/v1/users')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER_LIST)
|
||||
->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Users::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -410,7 +409,6 @@ App::get('/v1/users/:userId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -436,7 +434,6 @@ App::get('/v1/users/:userId/prefs')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -465,7 +462,6 @@ App::get('/v1/users/:userId/sessions')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Locale $locale) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -476,8 +472,7 @@ App::get('/v1/users/:userId/sessions')
|
||||
|
||||
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);
|
||||
|
||||
@@ -506,7 +501,6 @@ App::get('/v1/users/:userId/memberships')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -549,7 +543,6 @@ App::get('/v1/users/:userId/logs')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $userId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -568,7 +561,7 @@ App::get('/v1/users/:userId/logs')
|
||||
$output = [];
|
||||
|
||||
foreach ($logs as $i => &$log) {
|
||||
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
$log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
|
||||
$detector = new Detector($log['userAgent']);
|
||||
$detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
|
||||
@@ -592,14 +585,14 @@ App::get('/v1/users/:userId/logs')
|
||||
'clientEngineVersion' => $client['clientEngineVersion'],
|
||||
'deviceName' => $device['deviceName'],
|
||||
'deviceBrand' => $device['deviceBrand'],
|
||||
'deviceModel' => $device['deviceModel']
|
||||
'deviceModel' => $device['deviceModel'],
|
||||
]);
|
||||
|
||||
$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');
|
||||
@@ -634,7 +627,6 @@ App::patch('/v1/users/:userId/status')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, bool $status, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -670,7 +662,6 @@ App::patch('/v1/users/:userId/verification')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -706,7 +697,6 @@ App::patch('/v1/users/:userId/verification/phone')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, bool $phoneVerification, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -743,7 +733,6 @@ App::patch('/v1/users/:userId/name')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $name, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -753,7 +742,6 @@ App::patch('/v1/users/:userId/name')
|
||||
$user
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('search', \implode(' ', [$user->getId(), $user->getAttribute('email', ''), $name, $user->getAttribute('phone', '')]));
|
||||
;
|
||||
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
|
||||
@@ -784,7 +772,6 @@ App::patch('/v1/users/:userId/password')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $password, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -826,7 +813,6 @@ App::patch('/v1/users/:userId/email')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $email, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -872,7 +858,6 @@ App::patch('/v1/users/:userId/phone')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $number, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -883,7 +868,6 @@ App::patch('/v1/users/:userId/phone')
|
||||
->setAttribute('phone', $number)
|
||||
->setAttribute('phoneVerification', false)
|
||||
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name', ''), $user->getAttribute('email', ''), $number]));
|
||||
;
|
||||
|
||||
try {
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
@@ -918,7 +902,6 @@ App::patch('/v1/users/:userId/verification')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -951,7 +934,6 @@ App::patch('/v1/users/:userId/prefs')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, array $prefs, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -986,7 +968,6 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $sessionId, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1029,7 +1010,6 @@ App::delete('/v1/users/:userId/sessions')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1073,7 +1053,6 @@ App::delete('/v1/users/:userId')
|
||||
->inject('events')
|
||||
->inject('deletes')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1107,12 +1086,11 @@ App::get('/v1/users/usage')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USAGE_USERS)
|
||||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
|
||||
->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => "oauth-" . $value, \array_keys(Config::getParam('providers', [])))), true), 'Provider Name.', true)
|
||||
->param('provider', '', new WhiteList(\array_merge(['email', 'anonymous'], \array_map(fn ($value) => 'oauth-'.$value, \array_keys(Config::getParam('providers', [])))), true), 'Provider Name.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('register')
|
||||
->action(function (string $range, string $provider, Response $response, Database $dbForProject) {
|
||||
|
||||
$usage = [];
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||
$periods = [
|
||||
@@ -1194,7 +1172,7 @@ App::get('/v1/users/usage')
|
||||
'usersDelete' => $stats['users.$all.requests.delete'] ?? [],
|
||||
'sessionsCreate' => $stats['sessions.$all.requests.create'] ?? [],
|
||||
'sessionsProviderCreate' => $stats["sessions.$provider.requests.create"] ?? [],
|
||||
'sessionsDelete' => $stats['sessions.$all.requests.delete' ?? []]
|
||||
'sessionsDelete' => $stats['sessions.$all.requests.delete' ?? []],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
+74
-79
@@ -1,38 +1,38 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\View;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Domains\Domain;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Request\Filters\V12 as RequestV12;
|
||||
use Appwrite\Utopia\Request\Filters\V13 as RequestV13;
|
||||
use Appwrite\Utopia\Request\Filters\V14 as RequestV14;
|
||||
use Appwrite\Utopia\Request\Filters\V15 as RequestV15;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
|
||||
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
|
||||
use Appwrite\Utopia\Response\Filters\V13 as ResponseV13;
|
||||
use Appwrite\Utopia\Response\Filters\V14 as ResponseV14;
|
||||
use Appwrite\Utopia\Response\Filters\V15 as ResponseV15;
|
||||
use Appwrite\Utopia\View;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Validator\Hostname;
|
||||
use Appwrite\Utopia\Request\Filters\V12 as RequestV12;
|
||||
use Appwrite\Utopia\Request\Filters\V13 as RequestV13;
|
||||
use Appwrite\Utopia\Request\Filters\V14 as RequestV14;
|
||||
use Appwrite\Utopia\Request\Filters\V15 as RequestV15;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
@@ -82,12 +82,12 @@ App::init()
|
||||
|
||||
$domain = $request->getHostname();
|
||||
$domains = Config::getParam('domains', []);
|
||||
if (!array_key_exists($domain, $domains)) {
|
||||
$domain = new Domain(!empty($domain) ? $domain : '');
|
||||
if (! array_key_exists($domain, $domains)) {
|
||||
$domain = new Domain(! empty($domain) ? $domain : '');
|
||||
|
||||
if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) {
|
||||
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.');
|
||||
Console::warning($domain->get().' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
||||
} elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) {
|
||||
Console::warning('Skipping SSL certificates generation on ACME challenge.');
|
||||
} else {
|
||||
@@ -95,7 +95,7 @@ App::init()
|
||||
|
||||
$envDomain = App::getEnv('_APP_DOMAIN', '');
|
||||
$mainDomain = null;
|
||||
if (!empty($envDomain) && $envDomain !== 'localhost') {
|
||||
if (! empty($envDomain) && $envDomain !== 'localhost') {
|
||||
$mainDomain = $envDomain;
|
||||
} else {
|
||||
$domainDocument = $dbForConsole->findOne('domains', [Query::orderAsc('_id')]);
|
||||
@@ -103,13 +103,13 @@ App::init()
|
||||
}
|
||||
|
||||
if ($mainDomain !== $domain->get()) {
|
||||
Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.');
|
||||
Console::warning($domain->get().' is not a main domain. Skipping SSL certificate generation.');
|
||||
} else {
|
||||
$domainDocument = $dbForConsole->findOne('domains', [
|
||||
Query::equal('domain', [$domain->get()])
|
||||
Query::equal('domain', [$domain->get()]),
|
||||
]);
|
||||
|
||||
if (!$domainDocument) {
|
||||
if (! $domainDocument) {
|
||||
$domainDocument = new Document([
|
||||
'domain' => $domain->get(),
|
||||
'tld' => $domain->getSuffix(),
|
||||
@@ -120,7 +120,7 @@ App::init()
|
||||
|
||||
$domainDocument = $dbForConsole->createDocument('domains', $domainDocument);
|
||||
|
||||
Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...');
|
||||
Console::info('Issuing a TLS certificate for the main domain ('.$domain->get().') in a few seconds...');
|
||||
|
||||
(new Certificate())
|
||||
->setDomain($domainDocument)
|
||||
@@ -143,7 +143,7 @@ App::init()
|
||||
throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) {
|
||||
if (! empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) {
|
||||
throw new AppwriteException(AppwriteException::PROJECT_UNKNOWN);
|
||||
}
|
||||
|
||||
@@ -158,14 +158,14 @@ App::init()
|
||||
$refDomainOrigin = $origin;
|
||||
}
|
||||
|
||||
$refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $refDomainOrigin . (!empty($port) ? ':' . $port : '');
|
||||
$refDomain = (! empty($protocol) ? $protocol : $request->getProtocol()).'://'.$refDomainOrigin.(! empty($port) ? ':'.$port : '');
|
||||
|
||||
$refDomain = (!$route->getLabel('origin', false)) // This route is publicly accessible
|
||||
$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);
|
||||
$endDomain = new Domain((string) $origin);
|
||||
|
||||
Config::setParam(
|
||||
'domainVerification',
|
||||
@@ -175,11 +175,11 @@ App::init()
|
||||
|
||||
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
|
||||
@@ -221,12 +221,12 @@ App::init()
|
||||
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP.');
|
||||
}
|
||||
|
||||
return $response->redirect('https://' . $request->getHostname() . $request->getURI());
|
||||
return $response->redirect('https://'.$request->getHostname().$request->getURI());
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->getProtocol() === 'https') {
|
||||
$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
|
||||
@@ -236,8 +236,7 @@ App::init()
|
||||
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma')
|
||||
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
|
||||
->addHeader('Access-Control-Allow-Origin', $refDomain)
|
||||
->addHeader('Access-Control-Allow-Credentials', 'true')
|
||||
;
|
||||
->addHeader('Access-Control-Allow-Credentials', 'true');
|
||||
|
||||
/*
|
||||
* Validate Client Domain - Check to avoid CSRF attack
|
||||
@@ -248,7 +247,7 @@ App::init()
|
||||
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
||||
|
||||
if (
|
||||
!$originValidator->isValid($origin)
|
||||
! $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', ''))
|
||||
@@ -288,7 +287,7 @@ App::init()
|
||||
|
||||
$authKey = $request->getHeader('x-appwrite-key', '');
|
||||
|
||||
if (!empty($authKey)) { // API Key authentication
|
||||
if (! empty($authKey)) { // API Key authentication
|
||||
// Check if given key match project API keys
|
||||
$key = $project->find('secret', $authKey, 'keys');
|
||||
|
||||
@@ -300,7 +299,7 @@ App::init()
|
||||
$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'),
|
||||
]);
|
||||
@@ -309,8 +308,8 @@ App::init()
|
||||
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
|
||||
|
||||
$expire = $key->getAttribute('expire');
|
||||
if (!empty($expire) && $expire < DateTime::formatTz(DateTime::now())) {
|
||||
throw new AppwriteException(AppwriteException:: PROJECT_KEY_EXPIRED);
|
||||
if (! empty($expire) && $expire < DateTime::formatTz(DateTime::now())) {
|
||||
throw new AppwriteException(AppwriteException::PROJECT_KEY_EXPIRED);
|
||||
}
|
||||
|
||||
Authorization::setRole(Auth::USER_ROLE_APPS);
|
||||
@@ -327,7 +326,7 @@ App::init()
|
||||
$sdk = $request->getHeader('x-sdk-name', 'UNKNOWN');
|
||||
if ($sdkValidator->isValid($sdk)) {
|
||||
$sdks = $key->getAttribute('sdks', []);
|
||||
if (!in_array($sdk, $sdks)) {
|
||||
if (! in_array($sdk, $sdks)) {
|
||||
array_push($sdks, $sdk);
|
||||
$key->setAttribute('sdks', $sdks);
|
||||
|
||||
@@ -347,22 +346,22 @@ App::init()
|
||||
}
|
||||
|
||||
$service = $route->getLabel('sdk.namespace', '');
|
||||
if (!empty($service)) {
|
||||
if (! empty($service)) {
|
||||
if (
|
||||
array_key_exists($service, $project->getAttribute('services', []))
|
||||
&& !$project->getAttribute('services', [])[$service]
|
||||
&& !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
|
||||
&& ! $project->getAttribute('services', [])[$service]
|
||||
&& ! (Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
|
||||
) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
if (!\in_array($scope, $scopes)) {
|
||||
if (! \in_array($scope, $scopes)) {
|
||||
if ($project->isEmpty()) { // Check if permission is denied because project is missing
|
||||
throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')');
|
||||
throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')');
|
||||
}
|
||||
|
||||
if (false === $user->getAttribute('status')) { // Account is blocked
|
||||
@@ -378,7 +377,6 @@ App::options()
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (Request $request, Response $response) {
|
||||
|
||||
$origin = $request->getOrigin();
|
||||
|
||||
$response
|
||||
@@ -400,7 +398,6 @@ App::error()
|
||||
->inject('logger')
|
||||
->inject('loggerBreadcrumbs')
|
||||
->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, array $loggerBreadcrumbs) {
|
||||
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
$route = $utopia->match($request);
|
||||
|
||||
@@ -415,11 +412,11 @@ App::error()
|
||||
|
||||
$log = new Utopia\Logger\Log();
|
||||
|
||||
if (isset($user) && !$user->isEmpty()) {
|
||||
if (isset($user) && ! $user->isEmpty()) {
|
||||
$log->setUser(new User($user->getId()));
|
||||
}
|
||||
|
||||
$log->setNamespace("http");
|
||||
$log->setNamespace('http');
|
||||
$log->setServer(\gethostname());
|
||||
$log->setVersion($version);
|
||||
$log->setType(Log::TYPE_ERROR);
|
||||
@@ -431,7 +428,7 @@ App::error()
|
||||
$log->addTag('code', $error->getCode());
|
||||
$log->addTag('projectId', $project->getId());
|
||||
$log->addTag('hostname', $request->getHostname());
|
||||
$log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
||||
$log->addTag('locale', (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
||||
|
||||
$log->addExtra('file', $error->getFile());
|
||||
$log->addExtra('line', $error->getLine());
|
||||
@@ -439,7 +436,7 @@ App::error()
|
||||
$log->addExtra('detailedTrace', $error->getTrace());
|
||||
$log->addExtra('roles', Authorization::$roles);
|
||||
|
||||
$action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD");
|
||||
$action = $route->getLabel('sdk.namespace', 'UNKNOWN_NAMESPACE').'.'.$route->getLabel('sdk.method', 'UNKNOWN_METHOD');
|
||||
$log->setAction($action);
|
||||
|
||||
$isProduction = App::getEnv('_APP_ENV', 'development') === 'production';
|
||||
@@ -450,7 +447,7 @@ App::error()
|
||||
}
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Log pushed with status code: ' . $responseCode);
|
||||
Console::info('Log pushed with status code: '.$responseCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,17 +458,17 @@ App::error()
|
||||
$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());
|
||||
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 */
|
||||
@@ -488,7 +485,7 @@ App::error()
|
||||
}
|
||||
|
||||
/** Wrap all exceptions inside Appwrite\Extend\Exception */
|
||||
if (!($error instanceof AppwriteException)) {
|
||||
if (! ($error instanceof AppwriteException)) {
|
||||
$error = new AppwriteException(AppwriteException::GENERAL_UNKNOWN, $message, $code, $error);
|
||||
}
|
||||
|
||||
@@ -533,8 +530,7 @@ App::error()
|
||||
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
|
||||
->addHeader('Expires', '0')
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
->setStatusCode($code)
|
||||
;
|
||||
->setStatusCode($code);
|
||||
|
||||
$template = ($route) ? $route->getLabel('error', null) : null;
|
||||
|
||||
@@ -542,14 +538,13 @@ App::error()
|
||||
$layout = new View($template);
|
||||
|
||||
$layout
|
||||
->setParam('title', $project->getAttribute('name') . ' - Error')
|
||||
->setParam('title', $project->getAttribute('name').' - Error')
|
||||
->setParam('development', App::isDevelopment())
|
||||
->setParam('projectName', $project->getAttribute('name'))
|
||||
->setParam('projectURL', $project->getAttribute('url'))
|
||||
->setParam('message', $error->getMessage())
|
||||
->setParam('code', $code)
|
||||
->setParam('trace', $trace)
|
||||
;
|
||||
->setParam('trace', $trace);
|
||||
|
||||
$response->html($layout->render());
|
||||
}
|
||||
@@ -566,7 +561,7 @@ App::get('/robots.txt')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
$template = new View(__DIR__ . '/../views/general/robots.phtml');
|
||||
$template = new View(__DIR__.'/../views/general/robots.phtml');
|
||||
$response->text($template->render(false));
|
||||
});
|
||||
|
||||
@@ -576,7 +571,7 @@ App::get('/humans.txt')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
$template = new View(__DIR__ . '/../views/general/humans.phtml');
|
||||
$template = new View(__DIR__.'/../views/general/humans.phtml');
|
||||
$response->text($template->render(false));
|
||||
});
|
||||
|
||||
@@ -595,42 +590,42 @@ App::get('/.well-known/acme-challenge')
|
||||
...Text::ALPHABET_LOWER,
|
||||
...Text::ALPHABET_UPPER,
|
||||
'-',
|
||||
'_'
|
||||
'_',
|
||||
]);
|
||||
|
||||
if (!$validator->isValid($token) || \count($uriChunks) !== 4) {
|
||||
if (! $validator->isValid($token) || \count($uriChunks) !== 4) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, 'Invalid challenge token.');
|
||||
}
|
||||
|
||||
$base = \realpath(APP_STORAGE_CERTIFICATES);
|
||||
$absolute = \realpath($base . '/.well-known/acme-challenge/' . $token);
|
||||
$absolute = \realpath($base.'/.well-known/acme-challenge/'.$token);
|
||||
|
||||
if (!$base) {
|
||||
if (! $base) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Storage error');
|
||||
}
|
||||
|
||||
if (!$absolute) {
|
||||
if (! $absolute) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path');
|
||||
}
|
||||
|
||||
if (!\substr($absolute, 0, \strlen($base)) === $base) {
|
||||
if (! \substr($absolute, 0, \strlen($base)) === $base) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, 'Invalid path');
|
||||
}
|
||||
|
||||
if (!\file_exists($absolute)) {
|
||||
if (! \file_exists($absolute)) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path');
|
||||
}
|
||||
|
||||
$content = @\file_get_contents($absolute);
|
||||
|
||||
if (!$content) {
|
||||
if (! $content) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Failed to get contents');
|
||||
}
|
||||
|
||||
$response->text($content);
|
||||
});
|
||||
|
||||
include_once __DIR__ . '/shared/api.php';
|
||||
include_once __DIR__.'/shared/api.php';
|
||||
|
||||
foreach (Config::getParam('services', []) as $service) {
|
||||
include_once $service['controller'];
|
||||
|
||||
+24
-40
@@ -3,18 +3,17 @@
|
||||
global $utopia, $request, $response;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Validator\Host;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Storage\Validator\File;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Host;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Storage\Validator\File;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
|
||||
App::get('/v1/mock/tests/foo')
|
||||
->desc('Get Foo')
|
||||
@@ -220,9 +219,9 @@ App::get('/v1/mock/tests/general/headers')
|
||||
'x-sdk-version' => $request->getHeader('x-sdk-version'),
|
||||
];
|
||||
$res = array_map(function ($key, $value) {
|
||||
return $key . ': ' . $value;
|
||||
return $key.': '.$value;
|
||||
}, array_keys($res), $res);
|
||||
$res = implode("; ", $res);
|
||||
$res = implode('; ', $res);
|
||||
|
||||
$response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK);
|
||||
});
|
||||
@@ -241,14 +240,12 @@ App::get('/v1/mock/tests/general/download')
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response
|
||||
->setContentType('text/plain')
|
||||
->addHeader('Content-Disposition', 'attachment; filename="test.txt"')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->addHeader('X-Peak', \memory_get_peak_usage())
|
||||
->send("GET:/v1/mock/tests/general/download:passed")
|
||||
;
|
||||
->send('GET:/v1/mock/tests/general/download:passed');
|
||||
});
|
||||
|
||||
App::post('/v1/mock/tests/general/upload')
|
||||
@@ -271,14 +268,13 @@ App::post('/v1/mock/tests/general/upload')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (string $x, int $y, array $z, mixed $file, Request $request, Response $response) {
|
||||
|
||||
$file = $request->getFiles('file');
|
||||
|
||||
$contentRange = $request->getHeader('content-range');
|
||||
|
||||
$chunkSize = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
if (!empty($contentRange)) {
|
||||
if (! empty($contentRange)) {
|
||||
$start = $request->getContentRangeStart();
|
||||
$end = $request->getContentRangeEnd();
|
||||
$size = $request->getContentRangeSize();
|
||||
@@ -293,7 +289,7 @@ App::post('/v1/mock/tests/general/upload')
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Invalid content-range header');
|
||||
}
|
||||
|
||||
if ($start === 0 && !empty($id)) {
|
||||
if ($start === 0 && ! empty($id)) {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'First chunked request cannot have id header');
|
||||
}
|
||||
|
||||
@@ -317,7 +313,7 @@ App::post('/v1/mock/tests/general/upload')
|
||||
$response->json([
|
||||
'$id' => ID::custom('newfileid'),
|
||||
'chunksTotal' => $file['size'] / $chunkSize,
|
||||
'chunksUploaded' => $start / $chunkSize
|
||||
'chunksUploaded' => $start / $chunkSize,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
@@ -330,7 +326,7 @@ App::post('/v1/mock/tests/general/upload')
|
||||
}
|
||||
|
||||
if ($file['size'] !== 38756) {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size');
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size');
|
||||
}
|
||||
|
||||
if (\md5(\file_get_contents($file['tmp_name'])) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') {
|
||||
@@ -353,7 +349,6 @@ App::get('/v1/mock/tests/general/redirect')
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->redirect('/v1/mock/tests/general/redirect/done');
|
||||
});
|
||||
|
||||
@@ -387,7 +382,6 @@ App::get('/v1/mock/tests/general/set-cookie')
|
||||
->inject('response')
|
||||
->inject('request')
|
||||
->action(function (Response $response, Request $request) {
|
||||
|
||||
$response->addCookie('cookieName', 'cookieValue', \time() + 31536000, '/', $request->getHostname(), true, true);
|
||||
});
|
||||
|
||||
@@ -405,7 +399,6 @@ App::get('/v1/mock/tests/general/get-cookie')
|
||||
->label('sdk.mock', true)
|
||||
->inject('request')
|
||||
->action(function (Request $request) {
|
||||
|
||||
if ($request->getCookie('cookieName', '') !== 'cookieValue') {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Missing cookie value');
|
||||
}
|
||||
@@ -424,7 +417,6 @@ App::get('/v1/mock/tests/general/empty')
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
@@ -450,9 +442,9 @@ App::get('/v1/mock/tests/general/headers')
|
||||
'x-sdk-version' => $request->getHeader('x-sdk-version'),
|
||||
];
|
||||
$res = array_map(function ($key, $value) {
|
||||
return $key . ': ' . $value;
|
||||
return $key.': '.$value;
|
||||
}, array_keys($res), $res);
|
||||
$res = implode("; ", $res);
|
||||
$res = implode('; ', $res);
|
||||
|
||||
$response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK);
|
||||
});
|
||||
@@ -503,11 +495,9 @@ App::get('/v1/mock/tests/general/502-error')
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response
|
||||
->setStatusCode(502)
|
||||
->text('This is a text error')
|
||||
;
|
||||
->text('This is a text error');
|
||||
});
|
||||
|
||||
App::get('/v1/mock/tests/general/oauth2')
|
||||
@@ -522,8 +512,7 @@ App::get('/v1/mock/tests/general/oauth2')
|
||||
->param('state', '', new Text(1024), 'OAuth2 state.')
|
||||
->inject('response')
|
||||
->action(function (string $client_id, string $redirectURI, string $scope, string $state, Response $response) {
|
||||
|
||||
$response->redirect($redirectURI . '?' . \http_build_query(['code' => 'abcdef', 'state' => $state]));
|
||||
$response->redirect($redirectURI.'?'.\http_build_query(['code' => 'abcdef', 'state' => $state]));
|
||||
});
|
||||
|
||||
App::get('/v1/mock/tests/general/oauth2/token')
|
||||
@@ -540,7 +529,6 @@ App::get('/v1/mock/tests/general/oauth2/token')
|
||||
->param('refresh_token', '', new Text(100), 'OAuth2 refresh token.', true)
|
||||
->inject('response')
|
||||
->action(function (string $client_id, string $client_secret, string $grantType, string $redirectURI, string $code, string $refreshToken, Response $response) {
|
||||
|
||||
if ($client_id != '1') {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Invalid client ID');
|
||||
}
|
||||
@@ -552,7 +540,7 @@ App::get('/v1/mock/tests/general/oauth2/token')
|
||||
$responseJson = [
|
||||
'access_token' => '123456',
|
||||
'refresh_token' => 'tuvwxyz',
|
||||
'expires_in' => 14400
|
||||
'expires_in' => 14400,
|
||||
];
|
||||
|
||||
if ($grantType === 'authorization_code') {
|
||||
@@ -580,7 +568,6 @@ App::get('/v1/mock/tests/general/oauth2/user')
|
||||
->param('token', '', new Text(100), 'OAuth2 Access Token.')
|
||||
->inject('response')
|
||||
->action(function (string $token, Response $response) {
|
||||
|
||||
if ($token != '123456') {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Invalid token');
|
||||
}
|
||||
@@ -599,7 +586,6 @@ App::get('/v1/mock/tests/general/oauth2/success')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->json([
|
||||
'result' => 'success',
|
||||
]);
|
||||
@@ -612,7 +598,6 @@ App::get('/v1/mock/tests/general/oauth2/failure')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_BAD_REQUEST)
|
||||
->json([
|
||||
@@ -626,23 +611,22 @@ App::shutdown()
|
||||
->inject('response')
|
||||
->inject('request')
|
||||
->action(function (App $utopia, Response $response, Request $request) {
|
||||
|
||||
$result = [];
|
||||
$route = $utopia->match($request);
|
||||
$path = APP_STORAGE_CACHE . '/tests.json';
|
||||
$tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : [];
|
||||
$route = $utopia->match($request);
|
||||
$path = APP_STORAGE_CACHE.'/tests.json';
|
||||
$tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : [];
|
||||
|
||||
if (!\is_array($tests)) {
|
||||
if (! \is_array($tests)) {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Failed to read results', 500);
|
||||
}
|
||||
|
||||
$result[$route->getMethod() . ':' . $route->getPath()] = true;
|
||||
$result[$route->getMethod().':'.$route->getPath()] = true;
|
||||
|
||||
$tests = \array_merge($tests, $result);
|
||||
|
||||
if (!\file_put_contents($path, \json_encode($tests), LOCK_EX)) {
|
||||
if (! \file_put_contents($path, \json_encode($tests), LOCK_EX)) {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Failed to save results', 500);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document(['result' => $route->getMethod() . ':' . $route->getPath() . ':passed']), Response::MODEL_MOCK);
|
||||
$response->dynamic(new Document(['result' => $route->getMethod().':'.$route->getPath().':passed']), Response::MODEL_MOCK);
|
||||
});
|
||||
|
||||
@@ -5,15 +5,14 @@ use Appwrite\Event\Audit;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Usage\Stats;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Utopia\App;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
@@ -36,7 +35,7 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar
|
||||
$replace = $parts[1] ?? '';
|
||||
|
||||
$params = match ($namespace) {
|
||||
'user' => (array)$user,
|
||||
'user' => (array) $user,
|
||||
'request' => $requestParams,
|
||||
default => $responsePayload,
|
||||
};
|
||||
@@ -45,6 +44,7 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar
|
||||
$label = \str_replace($find, $params[$replace], $label);
|
||||
}
|
||||
}
|
||||
|
||||
return $label;
|
||||
};
|
||||
|
||||
@@ -104,7 +104,6 @@ App::init()
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Stats $usage, Delete $deletes, EventDatabase $database, Database $dbForProject, string $mode) use ($databaseListener) {
|
||||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
if ($project->isEmpty() && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope
|
||||
@@ -117,7 +116,7 @@ App::init()
|
||||
$abuseKeyLabel = $route->getLabel('abuse-key', 'url:{url},ip:{ip}');
|
||||
$timeLimitArray = [];
|
||||
|
||||
$abuseKeyLabel = (!is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel;
|
||||
$abuseKeyLabel = (! is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel;
|
||||
|
||||
foreach ($abuseKeyLabel as $abuseKey) {
|
||||
$timeLimit = new TimeLimit($abuseKey, $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForProject);
|
||||
@@ -125,7 +124,7 @@ App::init()
|
||||
->setParam('{userId}', $user->getId())
|
||||
->setParam('{userAgent}', $request->getUserAgent(''))
|
||||
->setParam('{ip}', $request->getIP())
|
||||
->setParam('{url}', $request->getHostname() . $route->getPath())
|
||||
->setParam('{url}', $request->getHostname().$route->getPath())
|
||||
->setParam('{method}', $request->getMethod());
|
||||
$timeLimitArray[] = $timeLimit;
|
||||
}
|
||||
@@ -138,8 +137,8 @@ App::init()
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,25 +152,24 @@ App::init()
|
||||
$response
|
||||
->addHeader('X-RateLimit-Limit', $limit)
|
||||
->addHeader('X-RateLimit-Remaining', $remaining)
|
||||
->addHeader('X-RateLimit-Reset', $time)
|
||||
;
|
||||
->addHeader('X-RateLimit-Reset', $time);
|
||||
}
|
||||
|
||||
$enabled = App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled';
|
||||
|
||||
if (
|
||||
$enabled // Abuse is enabled
|
||||
&& !$isAppUser // User is not API key
|
||||
&& !$isPrivilegedUser // User is not an admin
|
||||
&& ! $isAppUser // User is not API key
|
||||
&& ! $isPrivilegedUser // User is not an admin
|
||||
&& $abuse->check() // Route is rate-limited
|
||||
) {
|
||||
throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Background Jobs
|
||||
*/
|
||||
/*
|
||||
* Background Jobs
|
||||
*/
|
||||
$events
|
||||
->setEvent($route->getLabel('event', ''))
|
||||
->setProject($project)
|
||||
@@ -203,14 +201,14 @@ App::init()
|
||||
$useCache = $route->getLabel('cache', false);
|
||||
|
||||
if ($useCache) {
|
||||
$key = md5($request->getURI() . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER;
|
||||
$key = md5($request->getURI().implode('*', $request->getParams())).'*'.APP_CACHE_BUSTER;
|
||||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
|
||||
new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$project->getId())
|
||||
);
|
||||
$timestamp = 60 * 60 * 24 * 30;
|
||||
$data = $cache->load($key, $timestamp);
|
||||
|
||||
if (!empty($data)) {
|
||||
if (! empty($data)) {
|
||||
$data = json_decode($data, true);
|
||||
$parts = explode('/', $data['resourceType']);
|
||||
$type = $parts[0] ?? null;
|
||||
@@ -220,24 +218,24 @@ App::init()
|
||||
|
||||
$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(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$parts = explode('/', $data['resource']);
|
||||
$fileId = $parts[1] ?? null;
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -246,11 +244,10 @@ App::init()
|
||||
}
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp).' GMT')
|
||||
->addHeader('X-Appwrite-Cache', 'hit')
|
||||
->setContentType($data['contentType'])
|
||||
->send(base64_decode($data['payload']))
|
||||
;
|
||||
->send(base64_decode($data['payload']));
|
||||
|
||||
$route->setIsActive(false);
|
||||
} else {
|
||||
@@ -265,7 +262,6 @@ App::init()
|
||||
->inject('request')
|
||||
->inject('project')
|
||||
->action(function (App $utopia, Request $request, Document $project) {
|
||||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
@@ -366,10 +362,9 @@ App::shutdown()
|
||||
->inject('mode')
|
||||
->inject('dbForProject')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Event $events, Audit $audits, Stats $usage, Delete $deletes, EventDatabase $database, string $mode, Database $dbForProject) use ($parseLabel) {
|
||||
|
||||
$responsePayload = $response->getPayload();
|
||||
|
||||
if (!empty($events->getEvent())) {
|
||||
if (! empty($events->getEvent())) {
|
||||
if (empty($events->getPayload())) {
|
||||
$events->setPayload($responsePayload);
|
||||
}
|
||||
@@ -418,7 +413,7 @@ App::shutdown()
|
||||
roles: $target['roles'],
|
||||
options: [
|
||||
'permissionsChanged' => $target['permissionsChanged'],
|
||||
'userId' => $events->getParam('userId')
|
||||
'userId' => $events->getParam('userId'),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -432,27 +427,27 @@ App::shutdown()
|
||||
* Audit labels
|
||||
*/
|
||||
$pattern = $route->getLabel('audits.resource', null);
|
||||
if (!empty($pattern)) {
|
||||
if (! empty($pattern)) {
|
||||
$resource = $parseLabel($pattern, $responsePayload, $requestParams, $user);
|
||||
if (!empty($resource) && $resource !== $pattern) {
|
||||
if (! empty($resource) && $resource !== $pattern) {
|
||||
$audits->setResource($resource);
|
||||
}
|
||||
}
|
||||
|
||||
$pattern = $route->getLabel('audits.userId', null);
|
||||
if (!empty($pattern)) {
|
||||
if (! empty($pattern)) {
|
||||
$userId = $parseLabel($pattern, $responsePayload, $requestParams, $user);
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
$audits->setUser($user);
|
||||
}
|
||||
|
||||
if (!empty($audits->getResource()) && !empty($audits->getUser()->getId())) {
|
||||
if (! empty($audits->getResource()) && ! empty($audits->getUser()->getId())) {
|
||||
/**
|
||||
* audits.payload is switched to default true
|
||||
* in order to auto audit payload for all endpoints
|
||||
*/
|
||||
$pattern = $route->getLabel('audits.payload', true);
|
||||
if (!empty($pattern)) {
|
||||
if (! empty($pattern)) {
|
||||
$audits->setPayload($responsePayload);
|
||||
}
|
||||
|
||||
@@ -462,11 +457,11 @@ App::shutdown()
|
||||
$audits->trigger();
|
||||
}
|
||||
|
||||
if (!empty($deletes->getType())) {
|
||||
if (! empty($deletes->getType())) {
|
||||
$deletes->trigger();
|
||||
}
|
||||
|
||||
if (!empty($database->getType())) {
|
||||
if (! empty($database->getType())) {
|
||||
$database->trigger();
|
||||
}
|
||||
|
||||
@@ -478,35 +473,35 @@ App::shutdown()
|
||||
$resource = $resourceType = null;
|
||||
$data = $response->getPayload();
|
||||
|
||||
if (!empty($data['payload'])) {
|
||||
if (! empty($data['payload'])) {
|
||||
$pattern = $route->getLabel('cache.resource', null);
|
||||
if (!empty($pattern)) {
|
||||
if (! empty($pattern)) {
|
||||
$resource = $parseLabel($pattern, $responsePayload, $requestParams, $user);
|
||||
}
|
||||
|
||||
$pattern = $route->getLabel('cache.resourceType', null);
|
||||
if (!empty($pattern)) {
|
||||
if (! empty($pattern)) {
|
||||
$resourceType = $parseLabel($pattern, $responsePayload, $requestParams, $user);
|
||||
}
|
||||
|
||||
$key = md5($request->getURI() . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER;
|
||||
$key = md5($request->getURI().implode('*', $request->getParams())).'*'.APP_CACHE_BUSTER;
|
||||
$data = json_encode([
|
||||
'resourceType' => $resourceType,
|
||||
'resource' => $resource,
|
||||
'contentType' => $response->getContentType(),
|
||||
'payload' => base64_encode($data['payload']),
|
||||
]) ;
|
||||
'resourceType' => $resourceType,
|
||||
'resource' => $resource,
|
||||
'contentType' => $response->getContentType(),
|
||||
'payload' => base64_encode($data['payload']),
|
||||
]);
|
||||
|
||||
$signature = md5($data);
|
||||
$cacheLog = $dbForProject->getDocument('cache', $key);
|
||||
$cacheLog = $dbForProject->getDocument('cache', $key);
|
||||
$accessedAt = $cacheLog->getAttribute('accessedAt', '');
|
||||
$now = DateTime::now();
|
||||
if ($cacheLog->isEmpty()) {
|
||||
Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([
|
||||
'$id' => $key,
|
||||
'resource' => $resource,
|
||||
'accessedAt' => $now,
|
||||
'signature' => $signature,
|
||||
'$id' => $key,
|
||||
'resource' => $resource,
|
||||
'accessedAt' => $now,
|
||||
'signature' => $signature,
|
||||
])));
|
||||
} elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) {
|
||||
$cacheLog->setAttribute('accessedAt', $now);
|
||||
@@ -515,7 +510,7 @@ App::shutdown()
|
||||
|
||||
if ($signature !== $cacheLog->getAttribute('signature')) {
|
||||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
|
||||
new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$project->getId())
|
||||
);
|
||||
$cache->save($key, $data);
|
||||
}
|
||||
@@ -525,12 +520,12 @@ App::shutdown()
|
||||
if (
|
||||
App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled'
|
||||
&& $project->getId()
|
||||
&& !empty($route->getLabel('sdk.namespace', null))
|
||||
&& ! empty($route->getLabel('sdk.namespace', null))
|
||||
) { // Don't calculate console usage on admin mode
|
||||
$metric = $route->getLabel('usage.metric', '');
|
||||
$usageParams = $route->getLabel('usage.params', []);
|
||||
|
||||
if (!empty($metric)) {
|
||||
if (! empty($metric)) {
|
||||
$usage->setParam($metric, 1);
|
||||
foreach ($usageParams as $param) {
|
||||
$param = $parseLabel($param, $responsePayload, $requestParams, $user);
|
||||
@@ -544,7 +539,7 @@ App::shutdown()
|
||||
|
||||
$fileSize = 0;
|
||||
$file = $request->getFiles('file');
|
||||
if (!empty($file)) {
|
||||
if (! empty($file)) {
|
||||
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,6 @@ App::get('/console')
|
||||
->label('scope', 'home')
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
$fallback = file_get_contents(__DIR__ . '/../../../console/index.html');
|
||||
$fallback = file_get_contents(__DIR__.'/../../../console/index.html');
|
||||
$response->html($fallback);
|
||||
});
|
||||
|
||||
@@ -24,14 +24,14 @@ App::get('/versions')
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($language['enabled']) && !$language['enabled']) {
|
||||
if (isset($language['enabled']) && ! $language['enabled']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$platformKey = $platform['key'] ?? '';
|
||||
$languageKey = $language['key'] ?? '';
|
||||
$version = $language['version'] ?? '';
|
||||
$versions[$platformKey . '-' . $languageKey] = $version;
|
||||
$versions[$platformKey.'-'.$languageKey] = $version;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+76
-80
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use Appwrite\Runtimes\Runtimes;
|
||||
use Swoole\ConnectionPool;
|
||||
@@ -18,12 +18,12 @@ use Utopia\Logger\Logger;
|
||||
use Utopia\Orchestration\Adapter\DockerCLI;
|
||||
use Utopia\Orchestration\Orchestration;
|
||||
use Utopia\Storage\Device;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Device\Backblaze;
|
||||
use Utopia\Storage\Device\DOSpaces;
|
||||
use Utopia\Storage\Device\Linode;
|
||||
use Utopia\Storage\Device\Wasabi;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Device\S3;
|
||||
use Utopia\Storage\Device\Wasabi;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\Swoole\Request;
|
||||
use Utopia\Swoole\Response;
|
||||
@@ -33,15 +33,14 @@ use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
|
||||
Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
|
||||
|
||||
/** Constants */
|
||||
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);
|
||||
$activeRuntimes->column('created', Swoole\Table::TYPE_INT, 8);
|
||||
@@ -58,10 +57,10 @@ $orchestrationPool = new ConnectionPool(function () {
|
||||
$dockerUser = App::getEnv('DOCKERHUB_PULL_USERNAME', null);
|
||||
$dockerPass = App::getEnv('DOCKERHUB_PULL_PASSWORD', null);
|
||||
$orchestration = new Orchestration(new DockerCLI($dockerUser, $dockerPass));
|
||||
|
||||
return $orchestration;
|
||||
}, 10);
|
||||
|
||||
|
||||
/**
|
||||
* Create logger instance
|
||||
*/
|
||||
@@ -69,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);
|
||||
}
|
||||
@@ -83,7 +82,7 @@ function logError(Throwable $error, string $action, Utopia\Route $route = null)
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
$log = new Log();
|
||||
$log->setNamespace("executor");
|
||||
$log->setNamespace('executor');
|
||||
$log->setServer(\gethostname());
|
||||
$log->setVersion($version);
|
||||
$log->setType(Log::TYPE_ERROR);
|
||||
@@ -108,13 +107,13 @@ function logError(Throwable $error, string $action, Utopia\Route $route = null)
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Executor log pushed with status code: ' . $responseCode);
|
||||
Console::info('Executor log pushed with status code: '.$responseCode);
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: ' . get_class($error));
|
||||
Console::error('[Error] Message: ' . $error->getMessage());
|
||||
Console::error('[Error] File: ' . $error->getFile());
|
||||
Console::error('[Error] Line: ' . $error->getLine());
|
||||
Console::error('[Error] Type: '.get_class($error));
|
||||
Console::error('[Error] Message: '.$error->getMessage());
|
||||
Console::error('[Error] File: '.$error->getFile());
|
||||
Console::error('[Error] Line: '.$error->getLine());
|
||||
}
|
||||
|
||||
function getStorageDevice($root): Device
|
||||
@@ -129,6 +128,7 @@ function getStorageDevice($root): Device
|
||||
$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', '');
|
||||
@@ -136,6 +136,7 @@ function getStorageDevice($root): Device
|
||||
$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', '');
|
||||
@@ -143,6 +144,7 @@ function getStorageDevice($root): Device
|
||||
$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', '');
|
||||
@@ -150,6 +152,7 @@ function getStorageDevice($root): Device
|
||||
$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', '');
|
||||
@@ -157,12 +160,13 @@ function getStorageDevice($root): Device
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
App::post('/v1/runtimes')
|
||||
->desc("Create a new runtime server")
|
||||
->desc('Create a new runtime server')
|
||||
->param('runtimeId', '', new Text(64), 'Unique runtime ID.')
|
||||
->param('source', '', new Text(0), 'Path to source files.')
|
||||
->param('destination', '', new Text(0), 'Destination folder to store build files into.', true)
|
||||
@@ -196,7 +200,7 @@ App::post('/v1/runtimes')
|
||||
|
||||
$secret = \bin2hex(\random_bytes(16));
|
||||
|
||||
if (!$remove) {
|
||||
if (! $remove) {
|
||||
$activeRuntimes->set($runtimeId, [
|
||||
'id' => $containerId,
|
||||
'name' => $runtimeId,
|
||||
@@ -208,7 +212,7 @@ App::post('/v1/runtimes')
|
||||
}
|
||||
|
||||
try {
|
||||
Console::info('Building container : ' . $runtimeId);
|
||||
Console::info('Building container : '.$runtimeId);
|
||||
|
||||
/**
|
||||
* Temporary file paths in the executor
|
||||
@@ -219,19 +223,19 @@ App::post('/v1/runtimes')
|
||||
/**
|
||||
* Copy code files from source to a temporary location on the executor
|
||||
*/
|
||||
$sourceDevice = getStorageDevice("/");
|
||||
$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);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the mount folder
|
||||
*/
|
||||
if (!\file_exists(\dirname($tmpBuild))) {
|
||||
if (!@\mkdir(\dirname($tmpBuild), 0755, true)) {
|
||||
throw new Exception("Failed to create temporary directory", 500);
|
||||
if (! \file_exists(\dirname($tmpBuild))) {
|
||||
if (! @\mkdir(\dirname($tmpBuild), 0755, true)) {
|
||||
throw new Exception('Failed to create temporary directory', 500);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,10 +253,10 @@ App::post('/v1/runtimes')
|
||||
->setSwap((int) App::getEnv('_APP_FUNCTIONS_MEMORY_SWAP', 0));
|
||||
|
||||
/** Keep the container alive if we have commands to be executed */
|
||||
$entrypoint = !empty($commands) ? [
|
||||
$entrypoint = ! empty($commands) ? [
|
||||
'tail',
|
||||
'-f',
|
||||
'/dev/null'
|
||||
'/dev/null',
|
||||
] : [];
|
||||
|
||||
$containerId = $orchestration->run(
|
||||
@@ -269,8 +273,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',
|
||||
]
|
||||
);
|
||||
|
||||
@@ -283,7 +287,7 @@ App::post('/v1/runtimes')
|
||||
/**
|
||||
* Execute any commands if they were provided
|
||||
*/
|
||||
if (!empty($commands)) {
|
||||
if (! empty($commands)) {
|
||||
$status = $orchestration->execute(
|
||||
name: $runtimeId,
|
||||
command: $commands,
|
||||
@@ -292,27 +296,27 @@ App::post('/v1/runtimes')
|
||||
timeout: App::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900)
|
||||
);
|
||||
|
||||
if (!$status) {
|
||||
throw new Exception('Failed to build dependenices ' . $stderr, 500);
|
||||
if (! $status) {
|
||||
throw new Exception('Failed to build dependenices '.$stderr, 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move built code to expected build directory
|
||||
*/
|
||||
if (!empty($destination)) {
|
||||
if (! empty($destination)) {
|
||||
// Check if the build was successful by checking if file exists
|
||||
if (!\file_exists($tmpBuild)) {
|
||||
if (! \file_exists($tmpBuild)) {
|
||||
throw new Exception('Something went wrong during the build process', 500);
|
||||
}
|
||||
|
||||
$destinationDevice = getStorageDevice($destination);
|
||||
$outputPath = $destinationDevice->getPath(\uniqid() . '.' . \pathinfo('code.tar.gz', PATHINFO_EXTENSION));
|
||||
$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);
|
||||
};
|
||||
}
|
||||
|
||||
$container['outputPath'] = $outputPath;
|
||||
}
|
||||
@@ -334,27 +338,26 @@ App::post('/v1/runtimes')
|
||||
'duration' => $duration,
|
||||
]);
|
||||
|
||||
|
||||
if (!$remove) {
|
||||
if (! $remove) {
|
||||
$activeRuntimes->set($runtimeId, [
|
||||
'id' => $containerId,
|
||||
'name' => $runtimeId,
|
||||
'created' => $startTimeUnix,
|
||||
'updated' => $endTimeUnix,
|
||||
'status' => 'Up ' . \round($duration, 2) . 's',
|
||||
'status' => 'Up '.\round($duration, 2).'s',
|
||||
'key' => $secret,
|
||||
]);
|
||||
}
|
||||
|
||||
Console::success('Build Stage completed in ' . ($duration) . ' seconds');
|
||||
Console::success('Build Stage completed in '.($duration).' seconds');
|
||||
} catch (Throwable $th) {
|
||||
Console::error('Build failed: ' . $th->getMessage() . $stdout);
|
||||
Console::error('Build failed: '.$th->getMessage().$stdout);
|
||||
|
||||
throw new Exception($th->getMessage() . $stdout, 500);
|
||||
throw new Exception($th->getMessage().$stdout, 500);
|
||||
} finally {
|
||||
// Container cleanup
|
||||
if ($remove) {
|
||||
if (!empty($containerId)) {
|
||||
if (! empty($containerId)) {
|
||||
// If container properly created
|
||||
$orchestration->remove($containerId, true);
|
||||
$activeRuntimes->del($runtimeId);
|
||||
@@ -380,9 +383,8 @@ App::post('/v1/runtimes')
|
||||
->json($container);
|
||||
});
|
||||
|
||||
|
||||
App::get('/v1/runtimes')
|
||||
->desc("List currently active runtimes")
|
||||
->desc('List currently active runtimes')
|
||||
->inject('activeRuntimes')
|
||||
->inject('response')
|
||||
->action(function ($activeRuntimes, Response $response) {
|
||||
@@ -398,13 +400,12 @@ App::get('/v1/runtimes')
|
||||
});
|
||||
|
||||
App::get('/v1/runtimes/:runtimeId')
|
||||
->desc("Get a runtime by its ID")
|
||||
->desc('Get a runtime by its ID')
|
||||
->param('runtimeId', '', new Text(64), 'Runtime unique ID.')
|
||||
->inject('activeRuntimes')
|
||||
->inject('response')
|
||||
->action(function ($runtimeId, $activeRuntimes, Response $response) {
|
||||
|
||||
if (!$activeRuntimes->exists($runtimeId)) {
|
||||
if (! $activeRuntimes->exists($runtimeId)) {
|
||||
throw new Exception('Runtime not found', 404);
|
||||
}
|
||||
|
||||
@@ -422,18 +423,17 @@ App::delete('/v1/runtimes/:runtimeId')
|
||||
->inject('activeRuntimes')
|
||||
->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);
|
||||
}
|
||||
|
||||
Console::info('Deleting runtime: ' . $runtimeId);
|
||||
Console::info('Deleting runtime: '.$runtimeId);
|
||||
|
||||
try {
|
||||
$orchestration = $orchestrationPool->get();
|
||||
$orchestration->remove($runtimeId, true);
|
||||
$activeRuntimes->del($runtimeId);
|
||||
Console::success('Removed runtime container: ' . $runtimeId);
|
||||
Console::success('Removed runtime container: '.$runtimeId);
|
||||
} finally {
|
||||
$orchestrationPool->put($orchestration);
|
||||
}
|
||||
@@ -454,7 +454,6 @@ App::delete('/v1/runtimes/:runtimeId')
|
||||
->send();
|
||||
});
|
||||
|
||||
|
||||
App::post('/v1/execution')
|
||||
->desc('Create an execution')
|
||||
->param('runtimeId', '', new Text(64), 'The runtimeID to execute.')
|
||||
@@ -465,7 +464,7 @@ App::post('/v1/execution')
|
||||
->inject('response')
|
||||
->action(
|
||||
function (string $runtimeId, array $vars, string $data, $timeout, $activeRuntimes, Response $response) {
|
||||
if (!$activeRuntimes->exists($runtimeId)) {
|
||||
if (! $activeRuntimes->exists($runtimeId)) {
|
||||
throw new Exception('Runtime not found. Please create the runtime.', 404);
|
||||
}
|
||||
|
||||
@@ -488,7 +487,7 @@ App::post('/v1/execution')
|
||||
throw new Exception('Runtime secret not found. Please re-create the runtime.', 500);
|
||||
}
|
||||
|
||||
Console::info('Executing Runtime: ' . $runtimeId);
|
||||
Console::info('Executing Runtime: '.$runtimeId);
|
||||
|
||||
$execution = [];
|
||||
$executionStart = \microtime(true);
|
||||
@@ -505,9 +504,9 @@ App::post('/v1/execution')
|
||||
$body = \json_encode([
|
||||
'variables' => $vars,
|
||||
'payload' => $data,
|
||||
'timeout' => $timeout
|
||||
'timeout' => $timeout,
|
||||
]);
|
||||
\curl_setopt($ch, CURLOPT_URL, "http://" . $runtimeId . ":3000/");
|
||||
\curl_setopt($ch, CURLOPT_URL, 'http://'.$runtimeId.':3000/');
|
||||
\curl_setopt($ch, CURLOPT_POST, true);
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
@@ -516,9 +515,9 @@ App::post('/v1/execution')
|
||||
|
||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . \strlen($body),
|
||||
'x-internal-challenge: ' . $secret,
|
||||
'host: null'
|
||||
'Content-Length: '.\strlen($body),
|
||||
'x-internal-challenge: '.$secret,
|
||||
'host: null',
|
||||
]);
|
||||
|
||||
$executorResponse = \curl_exec($ch);
|
||||
@@ -538,10 +537,10 @@ App::post('/v1/execution')
|
||||
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);
|
||||
throw new Exception('An internal curl error has occurred within the executor! Error Msg: '.$error, 406);
|
||||
/** Any other CURL error */
|
||||
default:
|
||||
throw new Exception('An internal curl error has occurred within the executor! Error Msg: ' . $error, 500);
|
||||
throw new Exception('An internal curl error has occurred within the executor! Error Msg: '.$error, 500);
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
@@ -570,7 +569,7 @@ App::post('/v1/execution')
|
||||
$executionTime = ($executionEnd - $executionStart);
|
||||
$functionStatus = ($statusCode >= 500) ? 'failed' : 'completed';
|
||||
|
||||
Console::success('Function executed in ' . $executionTime . ' seconds, status: ' . $functionStatus);
|
||||
Console::success('Function executed in '.$executionTime.' seconds, status: '.$functionStatus);
|
||||
|
||||
$execution = [
|
||||
'status' => $functionStatus,
|
||||
@@ -593,11 +592,11 @@ App::post('/v1/execution')
|
||||
|
||||
App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
|
||||
|
||||
$http = new Server("0.0.0.0", 80);
|
||||
$http = new Server('0.0.0.0', 80);
|
||||
|
||||
/** Set Resources */
|
||||
App::setResource('orchestrationPool', fn() => $orchestrationPool);
|
||||
App::setResource('activeRuntimes', fn() => $activeRuntimes);
|
||||
App::setResource('orchestrationPool', fn () => $orchestrationPool);
|
||||
App::setResource('activeRuntimes', fn () => $activeRuntimes);
|
||||
|
||||
/** Set callbacks */
|
||||
App::error()
|
||||
@@ -607,7 +606,7 @@ App::error()
|
||||
->inject('response')
|
||||
->action(function (App $utopia, throwable $error, Request $request, Response $response) {
|
||||
$route = $utopia->match($request);
|
||||
logError($error, "httpError", $route);
|
||||
logError($error, 'httpError', $route);
|
||||
|
||||
switch ($error->getCode()) {
|
||||
case 400: // Error allowed publicly
|
||||
@@ -634,7 +633,7 @@ App::error()
|
||||
'file' => $error->getFile(),
|
||||
'line' => $error->getLine(),
|
||||
'trace' => $error->getTrace(),
|
||||
'version' => App::getEnv('_APP_VERSION', 'UNKNOWN')
|
||||
'version' => App::getEnv('_APP_VERSION', 'UNKNOWN'),
|
||||
];
|
||||
|
||||
$response
|
||||
@@ -659,7 +658,6 @@ App::init()
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$http->on('start', function ($http) {
|
||||
global $orchestrationPool;
|
||||
global $activeRuntimes;
|
||||
@@ -674,7 +672,7 @@ $http->on('start', function ($http) {
|
||||
go(function () use ($runtime, $orchestrationPool) {
|
||||
try {
|
||||
$orchestration = $orchestrationPool->get();
|
||||
Console::info('Warming up ' . $runtime['name'] . ' ' . $runtime['version'] . ' environment...');
|
||||
Console::info('Warming up '.$runtime['name'].' '.$runtime['version'].' environment...');
|
||||
$response = $orchestration->pull($runtime['image']);
|
||||
if ($response) {
|
||||
Console::success("Successfully Warmed up {$runtime['name']} {$runtime['version']}!");
|
||||
@@ -706,7 +704,7 @@ $http->on('start', function ($http) {
|
||||
$orchestration->remove($runtime->getName(), true);
|
||||
Console::success("Successfully removed {$runtime->getName()}");
|
||||
} catch (\Throwable $th) {
|
||||
Console::error('Orphan runtime deletion failed: ' . $th->getMessage());
|
||||
Console::error('Orphan runtime deletion failed: '.$th->getMessage());
|
||||
} finally {
|
||||
$orchestrationPool->put($orchestration);
|
||||
}
|
||||
@@ -736,7 +734,7 @@ $http->on('start', function ($http) {
|
||||
* Run a maintenance worker every MAINTENANCE_INTERVAL seconds to remove inactive runtimes
|
||||
*/
|
||||
Timer::tick(MAINTENANCE_INTERVAL * 1000, function () use ($orchestrationPool, $activeRuntimes) {
|
||||
Console::warning("Running maintenance task ...");
|
||||
Console::warning('Running maintenance task ...');
|
||||
foreach ($activeRuntimes as $runtime) {
|
||||
$inactiveThreshold = \time() - App::getEnv('_APP_FUNCTIONS_INACTIVE_THRESHOLD', 60);
|
||||
if ($runtime['updated'] < $inactiveThreshold) {
|
||||
@@ -747,7 +745,7 @@ $http->on('start', function ($http) {
|
||||
$activeRuntimes->del($runtime['name']);
|
||||
Console::success("Successfully removed {$runtime['name']}");
|
||||
} catch (\Throwable $th) {
|
||||
Console::error('Inactive Runtime deletion failed: ' . $th->getMessage());
|
||||
Console::error('Inactive Runtime deletion failed: '.$th->getMessage());
|
||||
} finally {
|
||||
$orchestrationPool->put($orchestration);
|
||||
}
|
||||
@@ -757,7 +755,6 @@ $http->on('start', function ($http) {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$http->on('beforeShutdown', function () {
|
||||
global $orchestrationPool;
|
||||
Console::info('Cleaning up containers before shutdown...');
|
||||
@@ -771,9 +768,9 @@ $http->on('beforeShutdown', function () {
|
||||
try {
|
||||
$orchestration = $orchestrationPool->get();
|
||||
$orchestration->remove($container->getId(), true);
|
||||
Console::info('Removed container ' . $container->getName());
|
||||
Console::info('Removed container '.$container->getName());
|
||||
} catch (\Throwable $th) {
|
||||
Console::error('Failed to remove container: ' . $container->getName());
|
||||
Console::error('Failed to remove container: '.$container->getName());
|
||||
} finally {
|
||||
$orchestrationPool->put($orchestration);
|
||||
}
|
||||
@@ -781,7 +778,6 @@ $http->on('beforeShutdown', function () {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) {
|
||||
$request = new Request($swooleRequest);
|
||||
$response = new Response($swooleResponse);
|
||||
@@ -790,14 +786,14 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
try {
|
||||
$app->run($request, $response);
|
||||
} catch (\Throwable $th) {
|
||||
logError($th, "serverError");
|
||||
logError($th, 'serverError');
|
||||
$swooleResponse->setStatusCode(500);
|
||||
$output = [
|
||||
'message' => 'Error: ' . $th->getMessage(),
|
||||
'message' => 'Error: '.$th->getMessage(),
|
||||
'code' => 500,
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine(),
|
||||
'trace' => $th->getTrace()
|
||||
'trace' => $th->getTrace(),
|
||||
];
|
||||
$swooleResponse->end(\json_encode($output));
|
||||
}
|
||||
|
||||
+36
-36
@@ -1,29 +1,29 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Swoole\Process;
|
||||
use Swoole\Http\Server;
|
||||
use Swoole\Http\Request as SwooleRequest;
|
||||
use Swoole\Http\Response as SwooleResponse;
|
||||
use Swoole\Http\Server;
|
||||
use Swoole\Process;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Swoole\Files;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Utopia\Swoole\Files;
|
||||
|
||||
$http = new Server("0.0.0.0", App::getEnv('PORT', 80));
|
||||
$http = new Server('0.0.0.0', App::getEnv('PORT', 80));
|
||||
|
||||
$payloadSize = 6 * (1024 * 1024); // 6MB
|
||||
$workerNumber = swoole_cpu_num() * intval(App::getEnv('_APP_WORKER_PER_CORE', 6));
|
||||
@@ -41,7 +41,7 @@ $http
|
||||
]);
|
||||
|
||||
$http->on('WorkerStart', function ($server, $workerId) {
|
||||
Console::success('Worker ' . ++$workerId . ' started successfully');
|
||||
Console::success('Worker '.++$workerId.' started successfully');
|
||||
});
|
||||
|
||||
$http->on('BeforeReload', function ($server, $workerId) {
|
||||
@@ -52,9 +52,9 @@ $http->on('AfterReload', function ($server, $workerId) {
|
||||
Console::success('Reload completed...');
|
||||
});
|
||||
|
||||
Files::load(__DIR__ . '/../console');
|
||||
Files::load(__DIR__.'/../console');
|
||||
|
||||
include __DIR__ . '/controllers/general.php';
|
||||
include __DIR__.'/controllers/general.php';
|
||||
|
||||
$http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
$app = new App('UTC');
|
||||
@@ -74,7 +74,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
} 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);
|
||||
}
|
||||
@@ -105,7 +105,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
}
|
||||
|
||||
if ($dbForConsole->getCollection(TimeLimit::COLLECTION)->isEmpty()) {
|
||||
$adapter = new TimeLimit("", 0, 1, $dbForConsole);
|
||||
$adapter = new TimeLimit('', 0, 1, $dbForConsole);
|
||||
$adapter->setup();
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
if (($collection['$collection'] ?? '') !== Database::METADATA) {
|
||||
continue;
|
||||
}
|
||||
if (!$dbForConsole->getCollection($key)->isEmpty()) {
|
||||
if (! $dbForConsole->getCollection($key)->isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
/**
|
||||
@@ -123,7 +123,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...');
|
||||
Console::success('[Setup] - Creating collection: '.$collection['$id'].'...');
|
||||
|
||||
$attributes = [];
|
||||
$indexes = [];
|
||||
@@ -138,7 +138,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
'format' => $attribute['format'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
$dbForConsole->createCollection($key, $attributes, $indexes);
|
||||
}
|
||||
|
||||
if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && !$dbForConsole->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), 'bucket_1')) {
|
||||
if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && ! $dbForConsole->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), 'bucket_1')) {
|
||||
Console::success('[Setup] - Creating default bucket...');
|
||||
$dbForConsole->createDocument('buckets', new Document([
|
||||
'$id' => ID::custom('default'),
|
||||
@@ -198,7 +198,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
'format' => $attribute['format'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -212,13 +212,13 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
]);
|
||||
}
|
||||
|
||||
$dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
|
||||
$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}");
|
||||
|
||||
// listen ctrl + c
|
||||
@@ -237,8 +237,8 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
|
||||
$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()));
|
||||
|
||||
return;
|
||||
@@ -260,7 +260,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
} catch (\Throwable $th) {
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
$logger = $app->getResource("logger");
|
||||
$logger = $app->getResource('logger');
|
||||
if ($logger) {
|
||||
try {
|
||||
/** @var Utopia\Database\Document $user */
|
||||
@@ -269,16 +269,16 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
// All good, user is optional information for logger
|
||||
}
|
||||
|
||||
$loggerBreadcrumbs = $app->getResource("loggerBreadcrumbs");
|
||||
$loggerBreadcrumbs = $app->getResource('loggerBreadcrumbs');
|
||||
$route = $app->match($request);
|
||||
|
||||
$log = new Utopia\Logger\Log();
|
||||
|
||||
if (isset($user) && !$user->isEmpty()) {
|
||||
if (isset($user) && ! $user->isEmpty()) {
|
||||
$log->setUser(new User($user->getId()));
|
||||
}
|
||||
|
||||
$log->setNamespace("http");
|
||||
$log->setNamespace('http');
|
||||
$log->setServer(\gethostname());
|
||||
$log->setVersion($version);
|
||||
$log->setType(Log::TYPE_ERROR);
|
||||
@@ -290,7 +290,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
$log->addTag('code', $th->getCode());
|
||||
// $log->addTag('projectId', $project->getId()); // TODO: Figure out how to get ProjectID, if it becomes relevant
|
||||
$log->addTag('hostname', $request->getHostname());
|
||||
$log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
||||
$log->addTag('locale', (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
||||
|
||||
$log->addExtra('file', $th->getFile());
|
||||
$log->addExtra('line', $th->getLine());
|
||||
@@ -298,7 +298,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
$log->addExtra('detailedTrace', $th->getTrace());
|
||||
$log->addExtra('roles', Authorization::$roles);
|
||||
|
||||
$action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD");
|
||||
$action = $route->getLabel('sdk.namespace', 'UNKNOWN_NAMESPACE').'.'.$route->getLabel('sdk.method', 'UNKNOWN_METHOD');
|
||||
$log->setAction($action);
|
||||
|
||||
$isProduction = App::getEnv('_APP_ENV', 'development') === 'production';
|
||||
@@ -309,18 +309,18 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
}
|
||||
|
||||
$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());
|
||||
|
||||
$swooleResponse->setStatusCode(500);
|
||||
|
||||
$output = ((App::isDevelopment())) ? [
|
||||
'message' => 'Error: ' . $th->getMessage(),
|
||||
'message' => 'Error: '.$th->getMessage(),
|
||||
'code' => 500,
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine(),
|
||||
|
||||
+173
-171
@@ -5,11 +5,9 @@
|
||||
*
|
||||
* 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');
|
||||
@@ -43,14 +41,13 @@ use Swoole\Database\PDOPool;
|
||||
use Swoole\Database\RedisConfig;
|
||||
use Swoole\Database\RedisPool;
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\DatetimeValidator;
|
||||
@@ -58,6 +55,7 @@ use Utopia\Database\Validator\Structure;
|
||||
use Utopia\Domains\Registrar;
|
||||
use Utopia\Domains\Registrar\OpenSRS;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Messaging\Adapters\SMS\Mock;
|
||||
use Utopia\Messaging\Adapters\SMS\Msg91;
|
||||
use Utopia\Messaging\Adapters\SMS\Telesign;
|
||||
@@ -73,8 +71,8 @@ use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Device\S3;
|
||||
use Utopia\Storage\Device\Wasabi;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\IP;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
@@ -82,7 +80,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;
|
||||
@@ -158,7 +156,7 @@ const DELETE_TYPE_REALTIME = 'realtime';
|
||||
const DELETE_TYPE_BUCKETS = 'buckets';
|
||||
const DELETE_TYPE_SESSIONS = 'sessions';
|
||||
const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp';
|
||||
const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource';
|
||||
const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource';
|
||||
// Compression type
|
||||
const COMPRESSION_TYPE_NONE = 'none';
|
||||
const COMPRESSION_TYPE_GZIP = 'gzip';
|
||||
@@ -184,39 +182,39 @@ 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('regions', __DIR__ . '/config/regions.php'); // List of available regions
|
||||
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('regions', __DIR__.'/config/regions.php'); // List of available regions
|
||||
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', ''));
|
||||
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', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,8 +270,7 @@ Database::addFilter(
|
||||
if (isset($formatOptions['min']) || isset($formatOptions['max'])) {
|
||||
$attribute
|
||||
->setAttribute('min', $formatOptions['min'])
|
||||
->setAttribute('max', $formatOptions['max'])
|
||||
;
|
||||
->setAttribute('max', $formatOptions['max']);
|
||||
}
|
||||
|
||||
return $value;
|
||||
@@ -385,7 +382,7 @@ Database::addFilter(
|
||||
return null;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn() => $database
|
||||
return Authorization::skip(fn () => $database
|
||||
->find('tokens', [
|
||||
Query::equal('userInternalId', [$document->getInternalId()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -399,7 +396,7 @@ Database::addFilter(
|
||||
return null;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn() => $database
|
||||
return Authorization::skip(fn () => $database
|
||||
->find('memberships', [
|
||||
Query::equal('userInternalId', [$document->getInternalId()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -441,7 +438,7 @@ Database::addFilter(
|
||||
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']));
|
||||
}
|
||||
@@ -460,6 +457,7 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_DATETIME, function () {
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_ENUM, function ($attribute) {
|
||||
$elements = $attribute['formatOptions']['elements'];
|
||||
|
||||
return new WhiteList($elements, true);
|
||||
}, Database::VAR_STRING);
|
||||
|
||||
@@ -474,12 +472,14 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_URL, function () {
|
||||
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) {
|
||||
$min = $attribute['formatOptions']['min'] ?? -INF;
|
||||
$max = $attribute['formatOptions']['max'] ?? INF;
|
||||
|
||||
return new Range($min, $max, Range::TYPE_FLOAT);
|
||||
}, Database::VAR_FLOAT);
|
||||
|
||||
@@ -495,16 +495,17 @@ $register->set('logger', function () {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Logger::hasProvider($providerName)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled");
|
||||
if (! Logger::hasProvider($providerName)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Logging provider not supported. Logging is disabled');
|
||||
}
|
||||
|
||||
$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 DB connection
|
||||
$dbHost = App::getEnv('_APP_DB_HOST', '');
|
||||
$dbPort = App::getEnv('_APP_DB_PORT', '');
|
||||
$dbUser = App::getEnv('_APP_DB_USER', '');
|
||||
@@ -540,7 +541,7 @@ $register->set('redisPool', function () {
|
||||
$redisAuth = '';
|
||||
|
||||
if ($redisUser && $redisPass) {
|
||||
$redisAuth = $redisUser . ':' . $redisPass;
|
||||
$redisAuth = $redisUser.':'.$redisPass;
|
||||
}
|
||||
|
||||
$pool = new RedisPool(
|
||||
@@ -555,7 +556,7 @@ $register->set('redisPool', function () {
|
||||
return $pool;
|
||||
});
|
||||
$register->set('influxdb', function () {
|
||||
// Register DB connection
|
||||
// Register DB connection
|
||||
$host = App::getEnv('_APP_INFLUXDB_HOST', '');
|
||||
$port = App::getEnv('_APP_INFLUXDB_PORT', '');
|
||||
|
||||
@@ -569,7 +570,7 @@ $register->set('influxdb', function () {
|
||||
return $client;
|
||||
});
|
||||
$register->set('statsd', function () {
|
||||
// Register DB connection
|
||||
// Register DB connection
|
||||
$host = App::getEnv('_APP_STATSD_HOST', 'telegraf');
|
||||
$port = App::getEnv('_APP_STATSD_PORT', 8125);
|
||||
|
||||
@@ -589,14 +590,14 @@ $register->set('smtp', function () {
|
||||
$mail->XMailer = 'Appwrite Mailer';
|
||||
$mail->Host = App::getEnv('_APP_SMTP_HOST', 'smtp');
|
||||
$mail->Port = App::getEnv('_APP_SMTP_PORT', 25);
|
||||
$mail->SMTPAuth = (!empty($username) && !empty($password));
|
||||
$mail->SMTPAuth = (! empty($username) && ! empty($password));
|
||||
$mail->Username = $username;
|
||||
$mail->Password = $password;
|
||||
$mail->SMTPSecure = App::getEnv('_APP_SMTP_SECURE', false);
|
||||
$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);
|
||||
@@ -607,29 +608,29 @@ $register->set('smtp', function () {
|
||||
return $mail;
|
||||
});
|
||||
$register->set('geodb', function () {
|
||||
return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2023-01.mmdb');
|
||||
return new Reader(__DIR__.'/assets/dbip/dbip-country-lite-2023-01.mmdb');
|
||||
});
|
||||
$register->set('db', function () {
|
||||
// This is usually for our workers or CLI commands scope
|
||||
// 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', '');
|
||||
$dbPass = App::getEnv('_APP_DB_PASS', '');
|
||||
$dbScheme = App::getEnv('_APP_DB_SCHEMA', '');
|
||||
|
||||
$pdo = new PDO("mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4", $dbUser, $dbPass, array(
|
||||
$pdo = new PDO("mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4", $dbUser, $dbPass, [
|
||||
PDO::ATTR_TIMEOUT => 3, // Seconds
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_EMULATE_PREPARES => true,
|
||||
PDO::ATTR_STRINGIFY_FETCHES => true,
|
||||
));
|
||||
]);
|
||||
|
||||
return $pdo;
|
||||
});
|
||||
$register->set('cache', function () {
|
||||
// This is usually for our workers or CLI commands scope
|
||||
// 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);
|
||||
@@ -644,78 +645,78 @@ $register->set('promiseAdapter', function () {
|
||||
* 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('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');
|
||||
Locale::setLanguageFromJSON('si', __DIR__ . '/config/locale/translations/si.json');
|
||||
Locale::setLanguageFromJSON('sk', __DIR__ . '/config/locale/translations/sk.json');
|
||||
Locale::setLanguageFromJSON('sl', __DIR__ . '/config/locale/translations/sl.json');
|
||||
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('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');
|
||||
Locale::setLanguageFromJSON('si', __DIR__.'/config/locale/translations/si.json');
|
||||
Locale::setLanguageFromJSON('sk', __DIR__.'/config/locale/translations/sk.json');
|
||||
Locale::setLanguageFromJSON('sl', __DIR__.'/config/locale/translations/sl.json');
|
||||
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');
|
||||
|
||||
\stream_context_set_default([ // Set global user agent and http settings
|
||||
'http' => [
|
||||
@@ -738,32 +739,32 @@ App::setResource('loggerBreadcrumbs', function () {
|
||||
return [];
|
||||
});
|
||||
|
||||
App::setResource('register', fn() => $register);
|
||||
App::setResource('register', fn () => $register);
|
||||
|
||||
App::setResource('locale', fn() => new Locale(App::getEnv('_APP_LOCALE', 'en')));
|
||||
App::setResource('locale', fn () => new Locale(App::getEnv('_APP_LOCALE', 'en')));
|
||||
|
||||
App::setResource('registrar', function(){
|
||||
$opensrs = new OpenSRS(
|
||||
App::getEnv('OPENSRS_KEY'),
|
||||
App::getEnv('OPENSRS_USERNAME'),
|
||||
'appwrite',
|
||||
'0p3n5R5@Appwrite',
|
||||
[
|
||||
'ns1.appwrite.io',
|
||||
'ns2.appwrite.io',
|
||||
]
|
||||
);
|
||||
|
||||
return new Registrar($opensrs);
|
||||
App::setResource('registrar', function () {
|
||||
$opensrs = new OpenSRS(
|
||||
App::getEnv('OPENSRS_KEY'),
|
||||
App::getEnv('OPENSRS_USERNAME'),
|
||||
'appwrite',
|
||||
'0p3n5R5@Appwrite',
|
||||
[
|
||||
'ns1.appwrite.io',
|
||||
'ns2.appwrite.io',
|
||||
]
|
||||
);
|
||||
|
||||
return new Registrar($opensrs);
|
||||
});
|
||||
|
||||
// Queues
|
||||
App::setResource('events', fn() => new Event('', ''));
|
||||
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('messaging', fn() => new Phone());
|
||||
App::setResource('events', fn () => new Event('', ''));
|
||||
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('messaging', fn () => new Phone());
|
||||
App::setResource('usage', function ($register) {
|
||||
return new Stats($register->get('statsd'));
|
||||
}, ['register']);
|
||||
@@ -784,7 +785,7 @@ App::setResource('clients', function ($request, $console, $project) {
|
||||
fn ($node) => $node['hostname'],
|
||||
\array_filter(
|
||||
$console->getAttribute('platforms', []),
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && isset($node['hostname']) && !empty($node['hostname']))
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && isset($node['hostname']) && ! empty($node['hostname']))
|
||||
)
|
||||
);
|
||||
|
||||
@@ -795,7 +796,7 @@ App::setResource('clients', function ($request, $console, $project) {
|
||||
fn ($node) => $node['hostname'],
|
||||
\array_filter(
|
||||
$project->getAttribute('platforms', []),
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB || $node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) && isset($node['hostname']) && !empty($node['hostname']))
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB || $node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) && isset($node['hostname']) && ! empty($node['hostname']))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -811,23 +812,22 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var string $mode */
|
||||
|
||||
Authorization::setDefaultStatus(true);
|
||||
|
||||
Auth::setCookieName('a_session_' . $project->getId());
|
||||
Auth::setCookieName('a_session_'.$project->getId());
|
||||
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
|
||||
if (APP_MODE_ADMIN === $mode) {
|
||||
Auth::setCookieName('a_session_' . $console->getId());
|
||||
Auth::setCookieName('a_session_'.$console->getId());
|
||||
$authDuration = Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
}
|
||||
|
||||
$session = Auth::decodeSession(
|
||||
$request->getCookie(
|
||||
Auth::$cookieName, // Get sessions
|
||||
$request->getCookie(Auth::$cookieName . '_legacy', '')
|
||||
$request->getCookie(Auth::$cookieName.'_legacy', '')
|
||||
)
|
||||
);// Get fallback session from old clients (no SameSite support)
|
||||
); // Get fallback session from old clients (no SameSite support)
|
||||
|
||||
// Get fallback session from clients who block 3rd-party cookies
|
||||
if ($response) {
|
||||
@@ -858,7 +858,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
|
||||
|
||||
if (
|
||||
$user->isEmpty() // Check a document has been found in the DB
|
||||
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration)
|
||||
|| ! Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration)
|
||||
) { // Validate user has valid login token
|
||||
$user = new Document(['$id' => ID::custom(''), '$collection' => 'users']);
|
||||
}
|
||||
@@ -873,13 +873,13 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
|
||||
|
||||
$authJWT = $request->getHeader('x-appwrite-jwt', '');
|
||||
|
||||
if (!empty($authJWT) && !$project->isEmpty()) { // JWT authentication
|
||||
if (! empty($authJWT) && ! $project->isEmpty()) { // JWT authentication
|
||||
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
|
||||
try {
|
||||
$payload = $jwt->decode($authJWT);
|
||||
} catch (JWTException $error) {
|
||||
throw new Exception(Exception::USER_JWT_INVALID, 'Failed to verify JWT. ' . $error->getMessage());
|
||||
throw new Exception(Exception::USER_JWT_INVALID, 'Failed to verify JWT. '.$error->getMessage());
|
||||
}
|
||||
|
||||
$jwtUserId = $payload['userId'] ?? '';
|
||||
@@ -901,14 +901,13 @@ 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') {
|
||||
return $console;
|
||||
}
|
||||
|
||||
$project = Authorization::skip(fn() => $dbForConsole->getDocument('projects', $projectId));
|
||||
$project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId));
|
||||
|
||||
return $project;
|
||||
}, ['dbForConsole', 'request', 'console']);
|
||||
@@ -942,8 +941,8 @@ App::setResource('console', function () {
|
||||
'limit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
|
||||
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, // 1 Year in seconds
|
||||
],
|
||||
'authWhitelistEmails' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
|
||||
'authWhitelistIPs' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
|
||||
'authWhitelistEmails' => (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
|
||||
'authWhitelistIPs' => (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
|
||||
]);
|
||||
}, []);
|
||||
|
||||
@@ -967,21 +966,20 @@ App::setResource('dbForConsole', function ($db, $cache) {
|
||||
return $database;
|
||||
}, ['db', 'cache']);
|
||||
|
||||
|
||||
App::setResource('deviceLocal', function () {
|
||||
return new Local();
|
||||
});
|
||||
|
||||
App::setResource('deviceFiles', function ($project) {
|
||||
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
|
||||
return getDevice(APP_STORAGE_UPLOADS.'/app-'.$project->getId());
|
||||
}, ['project']);
|
||||
|
||||
App::setResource('deviceFunctions', function ($project) {
|
||||
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
|
||||
return getDevice(APP_STORAGE_FUNCTIONS.'/app-'.$project->getId());
|
||||
}, ['project']);
|
||||
|
||||
App::setResource('deviceBuilds', function ($project) {
|
||||
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
|
||||
return getDevice(APP_STORAGE_BUILDS.'/app-'.$project->getId());
|
||||
}, ['project']);
|
||||
|
||||
function getDevice($root): Device
|
||||
@@ -996,6 +994,7 @@ function getDevice($root): Device
|
||||
$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', '');
|
||||
@@ -1003,6 +1002,7 @@ function getDevice($root): Device
|
||||
$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', '');
|
||||
@@ -1010,6 +1010,7 @@ function getDevice($root): Device
|
||||
$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', '');
|
||||
@@ -1017,6 +1018,7 @@ function getDevice($root): Device
|
||||
$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', '');
|
||||
@@ -1024,6 +1026,7 @@ function getDevice($root): Device
|
||||
$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);
|
||||
}
|
||||
}
|
||||
@@ -1076,7 +1079,6 @@ App::setResource('promiseAdapter', function ($register) {
|
||||
}, ['register']);
|
||||
|
||||
App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
|
||||
$complexity = function (int $complexity, array $args) {
|
||||
$queries = Query::parseQueries($args['queries'] ?? []);
|
||||
$query = Query::getByType($queries, Query::TYPE_LIMIT)[0] ?? null;
|
||||
@@ -1086,7 +1088,7 @@ App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
};
|
||||
|
||||
$attributes = function (int $limit, int $offset) use ($dbForProject) {
|
||||
$attrs = Authorization::skip(fn() => $dbForProject->find('attributes', [
|
||||
$attrs = Authorization::skip(fn () => $dbForProject->find('attributes', [
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
]));
|
||||
@@ -1116,7 +1118,7 @@ App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
|
||||
$params = [
|
||||
'list' => function (string $databaseId, string $collectionId, array $args) {
|
||||
return [ 'queries' => $args['queries']];
|
||||
return ['queries' => $args['queries']];
|
||||
},
|
||||
'create' => function (string $databaseId, string $collectionId, array $args) {
|
||||
$id = $args['id'] ?? 'unique()';
|
||||
|
||||
+18
-20
@@ -5,37 +5,35 @@
|
||||
*
|
||||
* 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 (
|
||||
[
|
||||
realpath(__DIR__ . '/../vendor/composer'),
|
||||
realpath(__DIR__ . '/../vendor/amphp'),
|
||||
realpath(__DIR__ . '/../vendor/felixfbecker'),
|
||||
realpath(__DIR__ . '/../vendor/twig/twig'),
|
||||
realpath(__DIR__ . '/../vendor/guzzlehttp/guzzle'),
|
||||
realpath(__DIR__ . '/../vendor/slickdeals'),
|
||||
realpath(__DIR__ . '/../vendor/psr/log'),
|
||||
realpath(__DIR__ . '/../vendor/matomo'),
|
||||
realpath(__DIR__ . '/../vendor/symfony'),
|
||||
realpath(__DIR__ . '/../vendor/mongodb'),
|
||||
realpath(__DIR__ . '/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload
|
||||
realpath(__DIR__ . '/../vendor/utopia-php/cache'), // TODO: remove memcache autoload
|
||||
realpath(__DIR__.'/../vendor/composer'),
|
||||
realpath(__DIR__.'/../vendor/amphp'),
|
||||
realpath(__DIR__.'/../vendor/felixfbecker'),
|
||||
realpath(__DIR__.'/../vendor/twig/twig'),
|
||||
realpath(__DIR__.'/../vendor/guzzlehttp/guzzle'),
|
||||
realpath(__DIR__.'/../vendor/slickdeals'),
|
||||
realpath(__DIR__.'/../vendor/psr/log'),
|
||||
realpath(__DIR__.'/../vendor/matomo'),
|
||||
realpath(__DIR__.'/../vendor/symfony'),
|
||||
realpath(__DIR__.'/../vendor/mongodb'),
|
||||
realpath(__DIR__.'/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload
|
||||
realpath(__DIR__.'/../vendor/utopia-php/cache'), // TODO: remove memcache autoload
|
||||
] as $key => $value
|
||||
) {
|
||||
if ($value !== false) {
|
||||
@@ -44,7 +42,7 @@ foreach (
|
||||
}
|
||||
|
||||
$preloader
|
||||
->paths(realpath(__DIR__ . '/../app/config'))
|
||||
->paths(realpath(__DIR__ . '/../app/controllers'))
|
||||
->paths(realpath(__DIR__ . '/../src'))
|
||||
->paths(realpath(__DIR__.'/../app/config'))
|
||||
->paths(realpath(__DIR__.'/../app/controllers'))
|
||||
->paths(realpath(__DIR__.'/../src'))
|
||||
->load();
|
||||
|
||||
+66
-65
@@ -3,6 +3,7 @@
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Swoole\Http\Request as SwooleRequest;
|
||||
use Swoole\Http\Response as SwooleResponse;
|
||||
@@ -12,24 +13,23 @@ use Swoole\Timer;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Registry\Registry;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Utopia\WebSocket\Server;
|
||||
use Utopia\WebSocket\Adapter;
|
||||
use Utopia\WebSocket\Server;
|
||||
|
||||
require_once __DIR__ . '/init.php';
|
||||
require_once __DIR__.'/init.php';
|
||||
|
||||
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
|
||||
@@ -64,7 +64,7 @@ $logError = function (Throwable $error, string $action) use ($register) {
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
$log = new Log();
|
||||
$log->setNamespace("realtime");
|
||||
$log->setNamespace('realtime');
|
||||
$log->setServer(\gethostname());
|
||||
$log->setVersion($version);
|
||||
$log->setType(Log::TYPE_ERROR);
|
||||
@@ -84,13 +84,13 @@ $logError = function (Throwable $error, string $action) use ($register) {
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Realtime log pushed with status code: ' . $responseCode);
|
||||
Console::info('Realtime log pushed with status code: '.$responseCode);
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: ' . get_class($error));
|
||||
Console::error('[Error] Message: ' . $error->getMessage());
|
||||
Console::error('[Error] File: ' . $error->getFile());
|
||||
Console::error('[Error] Line: ' . $error->getLine());
|
||||
Console::error('[Error] Type: '.get_class($error));
|
||||
Console::error('[Error] Message: '.$error->getMessage());
|
||||
Console::error('[Error] File: '.$error->getFile());
|
||||
Console::error('[Error] Line: '.$error->getLine());
|
||||
};
|
||||
|
||||
$server->error($logError);
|
||||
@@ -111,7 +111,7 @@ function getDatabase(Registry &$register, string $namespace)
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace($namespace);
|
||||
|
||||
if (!$database->exists($database->getDefaultDatabase(), 'realtime')) {
|
||||
if (! $database->exists($database->getDefaultDatabase(), 'realtime')) {
|
||||
throw new Exception('Collection not ready');
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ function getDatabase(Registry &$register, string $namespace)
|
||||
} catch (\Throwable $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(DATABASE_RECONNECT_SLEEP);
|
||||
}
|
||||
@@ -130,7 +130,7 @@ function getDatabase(Registry &$register, string $namespace)
|
||||
function () use ($register, $db, $redis) {
|
||||
$register->get('dbPool')->put($db);
|
||||
$register->get('redisPool')->put($redis);
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
||||
'$permissions' => [],
|
||||
'container' => $containerId,
|
||||
'timestamp' => DateTime::now(),
|
||||
'value' => '{}'
|
||||
'value' => '{}',
|
||||
]);
|
||||
|
||||
$statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document));
|
||||
@@ -187,7 +187,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
||||
|
||||
Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument));
|
||||
} catch (\Throwable $th) {
|
||||
call_user_func($logError, $th, "updateWorkerDocument");
|
||||
call_user_func($logError, $th, 'updateWorkerDocument');
|
||||
} finally {
|
||||
call_user_func($returnDatabase);
|
||||
}
|
||||
@@ -195,12 +195,12 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
||||
});
|
||||
|
||||
$server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime, $logError) {
|
||||
Console::success('Worker ' . $workerId . ' started successfully');
|
||||
Console::success('Worker '.$workerId.' started successfully');
|
||||
|
||||
$attempts = 0;
|
||||
$start = time();
|
||||
|
||||
Timer::tick(5000, function () use ($server, $register, $realtime, $stats, $logError) {
|
||||
Timer::tick(5000, function () use ($server, $register, $realtime, $stats) {
|
||||
/**
|
||||
* Sending current connections to project channels on the console project every 5 seconds.
|
||||
*/
|
||||
@@ -219,34 +219,34 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
foreach ($list as $document) {
|
||||
foreach (json_decode($document->getAttribute('value')) as $projectId => $value) {
|
||||
if (array_key_exists($projectId, $payload)) {
|
||||
$payload[$projectId] += $value;
|
||||
$payload[$projectId] += $value;
|
||||
} else {
|
||||
$payload[$projectId] = $value;
|
||||
$payload[$projectId] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($stats as $projectId => $value) {
|
||||
if (!array_key_exists($projectId, $payload)) {
|
||||
if (! array_key_exists($projectId, $payload)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$event = [
|
||||
'project' => 'console',
|
||||
'roles' => ['team:' . $stats->get($projectId, 'teamId')],
|
||||
'roles' => ['team:'.$stats->get($projectId, 'teamId')],
|
||||
'data' => [
|
||||
'events' => ['stats.connections'],
|
||||
'channels' => ['project'],
|
||||
'timestamp' => DateTime::formatTz(DateTime::now()),
|
||||
'payload' => [
|
||||
$projectId => $payload[$projectId]
|
||||
]
|
||||
]
|
||||
$projectId => $payload[$projectId],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$server->send($realtime->getSubscribers($event), json_encode([
|
||||
'type' => 'event',
|
||||
'data' => $event['data']
|
||||
'data' => $event['data'],
|
||||
]));
|
||||
}
|
||||
|
||||
@@ -265,13 +265,13 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
'events' => ['test.event'],
|
||||
'channels' => ['tests'],
|
||||
'timestamp' => DateTime::formatTz(DateTime::now()),
|
||||
'payload' => $payload
|
||||
]
|
||||
'payload' => $payload,
|
||||
],
|
||||
];
|
||||
|
||||
$server->send($realtime->getSubscribers($event), json_encode([
|
||||
'type' => 'event',
|
||||
'data' => $event['data']
|
||||
'data' => $event['data'],
|
||||
]));
|
||||
}
|
||||
});
|
||||
@@ -279,8 +279,8 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
while ($attempts < 300) {
|
||||
try {
|
||||
if ($attempts > 0) {
|
||||
Console::error('Pub/sub connection lost (lasted ' . (time() - $start) . ' seconds, worker: ' . $workerId . ').
|
||||
Attempting restart in 5 seconds (attempt #' . $attempts . ')');
|
||||
Console::error('Pub/sub connection lost (lasted '.(time() - $start).' seconds, worker: '.$workerId.').
|
||||
Attempting restart in 5 seconds (attempt #'.$attempts.')');
|
||||
sleep(5); // 5 sec delay between connection attempts
|
||||
}
|
||||
$start = time();
|
||||
@@ -291,9 +291,9 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
|
||||
if ($redis->ping(true)) {
|
||||
$attempts = 0;
|
||||
Console::success('Pub/sub connection established (worker: ' . $workerId . ')');
|
||||
Console::success('Pub/sub connection established (worker: '.$workerId.')');
|
||||
} else {
|
||||
Console::error('Pub/sub failed (worker: ' . $workerId . ')');
|
||||
Console::error('Pub/sub failed (worker: '.$workerId.')');
|
||||
}
|
||||
|
||||
$redis->subscribe(['realtime'], function (Redis $redis, string $channel, string $payload) use ($server, $workerId, $stats, $register, $realtime) {
|
||||
@@ -303,8 +303,8 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
$projectId = $event['project'];
|
||||
$userId = $event['userId'];
|
||||
|
||||
if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) {
|
||||
$connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId]));
|
||||
if ($realtime->hasSubscriber($projectId, 'user:'.$userId)) {
|
||||
$connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:'.$userId]));
|
||||
[$consoleDatabase, $returnConsoleDatabase] = getDatabase($register, '_console');
|
||||
$project = Authorization::skip(fn () => $consoleDatabase->getDocument('projects', $projectId));
|
||||
[$database, $returnDatabase] = getDatabase($register, "_{$project->getInternalId()}");
|
||||
@@ -322,17 +322,17 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
|
||||
$receivers = $realtime->getSubscribers($event);
|
||||
|
||||
if (App::isDevelopment() && !empty($receivers)) {
|
||||
Console::log("[Debug][Worker {$workerId}] Receivers: " . count($receivers));
|
||||
Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: " . json_encode($receivers));
|
||||
Console::log("[Debug][Worker {$workerId}] Event: " . $payload);
|
||||
if (App::isDevelopment() && ! empty($receivers)) {
|
||||
Console::log("[Debug][Worker {$workerId}] Receivers: ".count($receivers));
|
||||
Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: ".json_encode($receivers));
|
||||
Console::log("[Debug][Worker {$workerId}] Event: ".$payload);
|
||||
}
|
||||
|
||||
$server->send(
|
||||
$receivers,
|
||||
json_encode([
|
||||
'type' => 'event',
|
||||
'data' => $event['data']
|
||||
'data' => $event['data'],
|
||||
])
|
||||
);
|
||||
|
||||
@@ -341,12 +341,13 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
}
|
||||
});
|
||||
} catch (\Throwable $th) {
|
||||
call_user_func($logError, $th, "pubSubConnection");
|
||||
call_user_func($logError, $th, 'pubSubConnection');
|
||||
|
||||
Console::error('Pub/sub error: ' . $th->getMessage());
|
||||
Console::error('Pub/sub error: '.$th->getMessage());
|
||||
$register->get('redisPool')->put($redis);
|
||||
$attempts++;
|
||||
sleep(DATABASE_RECONNECT_SLEEP);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -417,7 +418,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
$origin = $request->getOrigin();
|
||||
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
||||
|
||||
if (!$originValidator->isValid($origin) && $project->getId() !== 'console') {
|
||||
if (! $originValidator->isValid($origin) && $project->getId() !== 'console') {
|
||||
throw new Exception($originValidator->getDescription(), 1008);
|
||||
}
|
||||
|
||||
@@ -440,25 +441,25 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
'type' => 'connected',
|
||||
'data' => [
|
||||
'channels' => array_keys($channels),
|
||||
'user' => $user
|
||||
]
|
||||
'user' => $user,
|
||||
],
|
||||
]));
|
||||
|
||||
$stats->set($project->getId(), [
|
||||
'projectId' => $project->getId(),
|
||||
'teamId' => $project->getAttribute('teamId')
|
||||
'teamId' => $project->getAttribute('teamId'),
|
||||
]);
|
||||
$stats->incr($project->getId(), 'connections');
|
||||
$stats->incr($project->getId(), 'connectionsTotal');
|
||||
} catch (\Throwable $th) {
|
||||
call_user_func($logError, $th, "initServer");
|
||||
call_user_func($logError, $th, 'initServer');
|
||||
|
||||
$response = [
|
||||
'type' => 'error',
|
||||
'data' => [
|
||||
'code' => $th->getCode(),
|
||||
'message' => $th->getMessage()
|
||||
]
|
||||
'message' => $th->getMessage(),
|
||||
],
|
||||
];
|
||||
|
||||
$server->send([$connection], json_encode($response));
|
||||
@@ -466,8 +467,8 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
|
||||
if (App::isDevelopment()) {
|
||||
Console::error('[Error] Connection Error');
|
||||
Console::error('[Error] Code: ' . $response['data']['code']);
|
||||
Console::error('[Error] Message: ' . $response['data']['message']);
|
||||
Console::error('[Error] Code: '.$response['data']['code']);
|
||||
Console::error('[Error] Message: '.$response['data']['message']);
|
||||
}
|
||||
|
||||
if ($th instanceof PDOException) {
|
||||
@@ -492,7 +493,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
$cache = new Cache(new RedisCache($redis));
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace("_console");
|
||||
$database->setNamespace('_console');
|
||||
$projectId = $realtime->connections[$connection]['projectId'];
|
||||
$project = $projectId === 'console' ? $app->getResource('console') : Authorization::skip(fn () => $database->getDocument('projects', $projectId));
|
||||
$database->setNamespace("_{$project->getInternalId()}");
|
||||
@@ -515,16 +516,16 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
|
||||
$message = json_decode($message, true);
|
||||
|
||||
if (is_null($message) || (!array_key_exists('type', $message) && !array_key_exists('data', $message))) {
|
||||
if (is_null($message) || (! array_key_exists('type', $message) && ! array_key_exists('data', $message))) {
|
||||
throw new Exception('Message format is not valid.', 1003);
|
||||
}
|
||||
|
||||
switch ($message['type']) {
|
||||
/**
|
||||
/**
|
||||
* This type is used to authenticate.
|
||||
*/
|
||||
case 'authentication':
|
||||
if (!array_key_exists('session', $message['data'])) {
|
||||
if (! array_key_exists('session', $message['data'])) {
|
||||
throw new Exception('Payload is not valid.', 1003);
|
||||
}
|
||||
|
||||
@@ -537,7 +538,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
|
||||
if (
|
||||
empty($user->getId()) // Check a document has been found in the DB
|
||||
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) // Validate user has valid login token
|
||||
|| ! Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) // Validate user has valid login token
|
||||
) {
|
||||
// cookie not valid
|
||||
throw new Exception('Session is not valid.', 1003);
|
||||
@@ -553,8 +554,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
'data' => [
|
||||
'to' => 'authentication',
|
||||
'success' => true,
|
||||
'user' => $user
|
||||
]
|
||||
'user' => $user,
|
||||
],
|
||||
]));
|
||||
|
||||
break;
|
||||
@@ -568,8 +569,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
'type' => 'error',
|
||||
'data' => [
|
||||
'code' => $th->getCode(),
|
||||
'message' => $th->getMessage()
|
||||
]
|
||||
'message' => $th->getMessage(),
|
||||
],
|
||||
];
|
||||
|
||||
$server->send([$connection], json_encode($response));
|
||||
@@ -589,7 +590,7 @@ $server->onClose(function (int $connection) use ($realtime, $stats) {
|
||||
}
|
||||
$realtime->unsubscribe($connection);
|
||||
|
||||
Console::info('Connection close: ' . $connection);
|
||||
Console::info('Connection close: '.$connection);
|
||||
});
|
||||
|
||||
$server->start();
|
||||
|
||||
+34
-35
@@ -3,12 +3,12 @@
|
||||
global $cli;
|
||||
|
||||
use Appwrite\ClamAV\Network;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Storage;
|
||||
|
||||
$cli
|
||||
->task('doctor')
|
||||
@@ -19,24 +19,24 @@ $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() . ')');
|
||||
if (! $domain->isKnown() || $domain->isTest()) {
|
||||
Console::log('🔴 Hostname has no public suffix ('.$domain->get().')');
|
||||
} else {
|
||||
Console::log('🟢 Hostname has a public suffix (' . $domain->get() . ')');
|
||||
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() . ')');
|
||||
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() . ')');
|
||||
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'))) {
|
||||
@@ -77,20 +77,19 @@ $cli
|
||||
Console::log('🟢 HTTPS force option is enabled');
|
||||
}
|
||||
|
||||
|
||||
$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 . ')');
|
||||
Console::log('🟢 Logging adapter is enabled ('.$providerName.')');
|
||||
}
|
||||
|
||||
\sleep(0.2);
|
||||
|
||||
try {
|
||||
Console::log("\n" . 'Checking connectivity...');
|
||||
Console::log("\n".'Checking connectivity...');
|
||||
} catch (\Throwable $th) {
|
||||
//throw $th;
|
||||
}
|
||||
@@ -150,7 +149,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 {
|
||||
@@ -174,24 +173,24 @@ $cli
|
||||
|
||||
foreach (
|
||||
[
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES,
|
||||
] as $key => $volume
|
||||
) {
|
||||
$device = new Local($volume);
|
||||
|
||||
if (\is_readable($device->getRoot())) {
|
||||
Console::success('🟢 ' . $key . ' Volume is readable');
|
||||
Console::success('🟢 '.$key.' Volume is readable');
|
||||
} else {
|
||||
Console::error('🔴 ' . $key . ' Volume is unreadable');
|
||||
Console::error('🔴 '.$key.' Volume is unreadable');
|
||||
}
|
||||
|
||||
if (\is_writable($device->getRoot())) {
|
||||
Console::success('🟢 ' . $key . ' Volume is writeable');
|
||||
Console::success('🟢 '.$key.' Volume is writeable');
|
||||
} else {
|
||||
Console::error('🔴 ' . $key . ' Volume is unwriteable');
|
||||
Console::error('🔴 '.$key.' Volume is unwriteable');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,10 +201,10 @@ $cli
|
||||
|
||||
foreach (
|
||||
[
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES,
|
||||
] as $key => $volume
|
||||
) {
|
||||
$device = new Local($volume);
|
||||
@@ -213,31 +212,31 @@ $cli
|
||||
$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);
|
||||
Console::success('🟢 '.$message);
|
||||
} else {
|
||||
Console::error('🔴 ' . $message);
|
||||
Console::error('🔴 '.$message);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
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 . '! 🥳');
|
||||
Console::info('You are running the latest version of '.APP_NAME.'! 🥳');
|
||||
} else {
|
||||
Console::info('A new version (' . $version['version'] . ') is available! 🥳' . "\n");
|
||||
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");
|
||||
}
|
||||
});
|
||||
|
||||
+33
-31
@@ -57,19 +57,19 @@ $cli
|
||||
Console::success('Starting Appwrite installation...');
|
||||
|
||||
// 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));
|
||||
if (null !== $path && ! \file_exists(\dirname($path))) {
|
||||
if (! @\mkdir(\dirname($path), 0755, true)) {
|
||||
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) {
|
||||
$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;
|
||||
@@ -78,14 +78,14 @@ $cli
|
||||
} catch (\Throwable $th) {
|
||||
$ports = [
|
||||
$defaultHTTPPort => $defaultHTTPPort,
|
||||
$defaultHTTPSPort => $defaultHTTPSPort
|
||||
$defaultHTTPSPort => $defaultHTTPSPort,
|
||||
];
|
||||
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 (! $service) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -103,11 +103,11 @@ $cli
|
||||
}
|
||||
}
|
||||
|
||||
$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);
|
||||
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) {
|
||||
@@ -135,40 +135,44 @@ $cli
|
||||
}
|
||||
|
||||
if (empty($httpPort)) {
|
||||
$httpPort = Console::confirm('Choose your server HTTP port: (default: ' . $defaultHTTPPort . ')');
|
||||
$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 . ')');
|
||||
$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 (! empty($var['filter']) && ($interactive !== 'Y' || ! Console::isInteractive())) {
|
||||
if ($data && $var['default'] !== null) {
|
||||
$input[$var['name']] = $var['default'];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($var['filter'] === 'token') {
|
||||
$input[$var['name']] = Auth::tokenGenerator();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
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']])) {
|
||||
$input[$var['name']] = $var['default'];
|
||||
@@ -178,38 +182,36 @@ $cli
|
||||
if ($input[$var['name']] !== 'localhost') {
|
||||
Console::warning("\nIf you haven't already done so, set the following record for {$input[$var['name']]} on your DNS provider:\n");
|
||||
$mask = "%-15.15s %-10.10s %-30.30s\n";
|
||||
printf($mask, "Type", "Name", "Value");
|
||||
printf($mask, "A or AAAA", "@", "<YOUR PUBLIC IP>");
|
||||
printf($mask, 'Type', 'Name', 'Value');
|
||||
printf($mask, 'A or AAAA', '@', '<YOUR PUBLIC IP>');
|
||||
Console::warning("\nUse 'AAAA' if you're using an IPv6 address and 'A' if you're using an IPv4 address.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$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)
|
||||
->setParam('httpsPort', $httpsPort)
|
||||
->setParam('version', APP_VERSION_STABLE)
|
||||
->setParam('organization', $organization)
|
||||
->setParam('image', $image)
|
||||
;
|
||||
->setParam('image', $image);
|
||||
|
||||
$templateForEnv
|
||||
->setParam('vars', $input)
|
||||
;
|
||||
->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);
|
||||
}
|
||||
@@ -220,7 +222,7 @@ $cli
|
||||
|
||||
foreach ($input as $key => $value) {
|
||||
if ($value) {
|
||||
$env .= $key . '=' . \escapeshellarg($value) . ' ';
|
||||
$env .= $key.'='.\escapeshellarg($value).' ';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,13 +232,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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,16 +3,15 @@
|
||||
global $cli;
|
||||
global $register;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Delete;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
@@ -30,7 +29,7 @@ function getConsoleDB(): Database
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace('_console'); // Main DB
|
||||
|
||||
if (!$database->exists($database->getDefaultDatabase(), 'certificates')) {
|
||||
if (! $database->exists($database->getDefaultDatabase(), 'certificates')) {
|
||||
throw new \Exception('Console project not ready');
|
||||
}
|
||||
|
||||
@@ -38,7 +37,7 @@ function getConsoleDB(): Database
|
||||
} 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(DATABASE_RECONNECT_SLEEP);
|
||||
}
|
||||
@@ -52,7 +51,7 @@ $cli
|
||||
->desc('Schedules maintenance tasks and publishes them to resque')
|
||||
->action(function () {
|
||||
Console::title('Maintenance V1');
|
||||
Console::success(APP_NAME . ' maintenance process v1 has started');
|
||||
Console::success(APP_NAME.' maintenance process v1 has started');
|
||||
|
||||
function notifyDeleteExecutionLogs(int $interval)
|
||||
{
|
||||
@@ -106,20 +105,19 @@ $cli
|
||||
$time = DateTime::now();
|
||||
|
||||
$certificates = $dbForConsole->find('certificates', [
|
||||
Query::lessThan('attempts', 5), // Maximum 5 attempts
|
||||
Query::lessThanEqual('renewDate', $time), // includes 60 days cooldown (we have 30 days to renew)
|
||||
Query::limit(200), // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains)
|
||||
Query::lessThan('attempts', 5), // Maximum 5 attempts
|
||||
Query::lessThanEqual('renewDate', $time), // includes 60 days cooldown (we have 30 days to renew)
|
||||
Query::limit(200), // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains)
|
||||
]);
|
||||
|
||||
|
||||
if (\count($certificates) > 0) {
|
||||
Console::info("[{$time}] Found " . \count($certificates) . " certificates for renewal, scheduling jobs.");
|
||||
Console::info("[{$time}] Found ".\count($certificates).' certificates for renewal, scheduling jobs.');
|
||||
|
||||
$event = new Certificate();
|
||||
foreach ($certificates as $certificate) {
|
||||
$event
|
||||
->setDomain(new Document([
|
||||
'domain' => $certificate->getAttribute('domain')
|
||||
'domain' => $certificate->getAttribute('domain'),
|
||||
]))
|
||||
->trigger();
|
||||
}
|
||||
@@ -130,7 +128,6 @@ $cli
|
||||
|
||||
function notifyDeleteCache($interval)
|
||||
{
|
||||
|
||||
(new Delete())
|
||||
->setType(DELETE_TYPE_CACHE_BY_TIMESTAMP)
|
||||
->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * $interval))
|
||||
|
||||
+10
-9
@@ -2,11 +2,11 @@
|
||||
|
||||
global $cli, $register;
|
||||
|
||||
use Utopia\CLI\Console;
|
||||
use Appwrite\Migration\Migration;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
@@ -19,7 +19,7 @@ function clearProjectsCache(Redis $redis, Document $project)
|
||||
try {
|
||||
$redis->del($redis->keys("cache-_{$project->getInternalId()}:*"));
|
||||
} catch (\Throwable $th) {
|
||||
Console::error('Failed to clear project ("' . $project->getId() . '") cache with error: ' . $th->getMessage());
|
||||
Console::error('Failed to clear project ("'.$project->getId().'") cache with error: '.$th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,15 +28,16 @@ $cli
|
||||
->param('version', APP_VERSION_STABLE, new Text(32), 'Version to migrate to.', true)
|
||||
->action(function ($version) use ($register) {
|
||||
Authorization::disable();
|
||||
if (!array_key_exists($version, Migration::$versions)) {
|
||||
if (! array_key_exists($version, Migration::$versions)) {
|
||||
Console::error("Version {$version} not found.");
|
||||
Console::exit(1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$app = new App('UTC');
|
||||
|
||||
Console::success('Starting Data Migration to version ' . $version);
|
||||
Console::success('Starting Data Migration to version '.$version);
|
||||
|
||||
$db = $register->get('db', true);
|
||||
$redis = $register->get('cache', true);
|
||||
@@ -68,10 +69,10 @@ $cli
|
||||
$totalProjects = $consoleDB->count('projects') + 1;
|
||||
}
|
||||
|
||||
$class = 'Appwrite\\Migration\\Version\\' . Migration::$versions[$version];
|
||||
$class = 'Appwrite\\Migration\\Version\\'.Migration::$versions[$version];
|
||||
$migration = new $class();
|
||||
|
||||
while (!empty($projects)) {
|
||||
while (! empty($projects)) {
|
||||
foreach ($projects as $project) {
|
||||
/**
|
||||
* Skip user projects with id 'console'
|
||||
@@ -88,7 +89,7 @@ $cli
|
||||
->execute();
|
||||
} catch (\Throwable $th) {
|
||||
throw $th;
|
||||
Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage());
|
||||
Console::error('Failed to update project ("'.$project->getId().'") version with error: '.$th->getMessage());
|
||||
}
|
||||
|
||||
clearProjectsCache($redis, $project);
|
||||
@@ -100,7 +101,7 @@ $cli
|
||||
$offset = $offset + $limit;
|
||||
$count = $count + $sum;
|
||||
|
||||
Console::log('Migrated ' . $count . '/' . $totalProjects . ' projects...');
|
||||
Console::log('Migrated '.$count.'/'.$totalProjects.' projects...');
|
||||
}
|
||||
|
||||
Swoole\Event::wait(); // Wait for Coroutines to finish
|
||||
|
||||
+39
-39
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\SDK\Language\Android;
|
||||
use Appwrite\SDK\Language\Apple;
|
||||
use Appwrite\SDK\Language\CLI;
|
||||
use Appwrite\SDK\Language\Dart;
|
||||
use Appwrite\SDK\Language\Deno;
|
||||
@@ -15,7 +16,6 @@ use Appwrite\SDK\Language\Python;
|
||||
use Appwrite\SDK\Language\REST;
|
||||
use Appwrite\SDK\Language\Ruby;
|
||||
use Appwrite\SDK\Language\Swift;
|
||||
use Appwrite\SDK\Language\Apple;
|
||||
use Appwrite\SDK\Language\Web;
|
||||
use Appwrite\SDK\SDK;
|
||||
use Appwrite\Spec\Swagger2;
|
||||
@@ -26,14 +26,14 @@ $cli
|
||||
->task('sdks')
|
||||
->action(function () {
|
||||
$platforms = Config::getParam('platforms');
|
||||
$selectedPlatform = Console::confirm('Choose Platform ("' . APP_PLATFORM_CLIENT . '", "' . APP_PLATFORM_SERVER . '", "' . APP_PLATFORM_CONSOLE . '" or "*" for all):');
|
||||
$selectedPlatform = Console::confirm('Choose Platform ("'.APP_PLATFORM_CLIENT.'", "'.APP_PLATFORM_SERVER.'", "'.APP_PLATFORM_CONSOLE.'" or "*" for all):');
|
||||
$selectedSDK = \strtolower(Console::confirm('Choose SDK ("*" for all):'));
|
||||
$version = Console::confirm('Choose an Appwrite version');
|
||||
$git = (Console::confirm('Should we use git push? (yes/no)') == 'yes');
|
||||
$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', '0.15.x', '1.0.x', '1.1.x', '1.2.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', '0.15.x', '1.0.x', '1.1.x', '1.2.x', 'latest'])) {
|
||||
throw new Exception('Unknown version given');
|
||||
}
|
||||
|
||||
@@ -47,30 +47,31 @@ $cli
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$language['enabled']) {
|
||||
Console::warning($language['name'] . ' for ' . $platform['name'] . ' is disabled');
|
||||
if (! $language['enabled']) {
|
||||
Console::warning($language['name'].' for '.$platform['name'].' is disabled');
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
Console::info('Fetching API Spec for ' . $language['name'] . ' for ' . $platform['name'] . ' (version: ' . $version . ')');
|
||||
Console::info('Fetching API Spec for '.$language['name'].' for '.$platform['name'].' (version: '.$version.')');
|
||||
|
||||
$spec = file_get_contents(__DIR__ . '/../config/specs/swagger2-' . $version . '-' . $language['family'] . '.json');
|
||||
$spec = file_get_contents(__DIR__.'/../config/specs/swagger2-'.$version.'-'.$language['family'].'.json');
|
||||
|
||||
$cover = 'https://appwrite.io/images/github.png';
|
||||
$result = \realpath(__DIR__ . '/..') . '/sdks/' . $key . '-' . $language['key'];
|
||||
$resultExamples = \realpath(__DIR__ . '/../..') . '/docs/examples/' . $version . '/' . $key . '-' . $language['key'];
|
||||
$target = \realpath(__DIR__ . '/..') . '/sdks/git/' . $language['key'] . '/';
|
||||
$readme = \realpath(__DIR__ . '/../../docs/sdks/' . $language['key'] . '/README.md');
|
||||
$result = \realpath(__DIR__.'/..').'/sdks/'.$key.'-'.$language['key'];
|
||||
$resultExamples = \realpath(__DIR__.'/../..').'/docs/examples/'.$version.'/'.$key.'-'.$language['key'];
|
||||
$target = \realpath(__DIR__.'/..').'/sdks/git/'.$language['key'].'/';
|
||||
$readme = \realpath(__DIR__.'/../../docs/sdks/'.$language['key'].'/README.md');
|
||||
$readme = ($readme) ? \file_get_contents($readme) : '';
|
||||
$gettingStarted = \realpath(__DIR__ . '/../../docs/sdks/' . $language['key'] . '/GETTING_STARTED.md');
|
||||
$gettingStarted = \realpath(__DIR__.'/../../docs/sdks/'.$language['key'].'/GETTING_STARTED.md');
|
||||
$gettingStarted = ($gettingStarted) ? \file_get_contents($gettingStarted) : '';
|
||||
$examples = \realpath(__DIR__ . '/../../docs/sdks/' . $language['key'] . '/EXAMPLES.md');
|
||||
$examples = \realpath(__DIR__.'/../../docs/sdks/'.$language['key'].'/EXAMPLES.md');
|
||||
$examples = ($examples) ? \file_get_contents($examples) : '';
|
||||
$changelog = \realpath(__DIR__ . '/../../docs/sdks/' . $language['key'] . '/CHANGELOG.md');
|
||||
$changelog = \realpath(__DIR__.'/../../docs/sdks/'.$language['key'].'/CHANGELOG.md');
|
||||
$changelog = ($changelog) ? \file_get_contents($changelog) : '# Change Log';
|
||||
$warning = '**This SDK is compatible with Appwrite server version ' . $version . '. For older versions, please check [previous releases](' . $language['url'] . '/releases).**';
|
||||
$warning = '**This SDK is compatible with Appwrite server version '.$version.'. For older versions, please check [previous releases]('.$language['url'].'/releases).**';
|
||||
$license = 'BSD-3-Clause';
|
||||
$licenseContent = 'Copyright (c) ' . date('Y') . ' Appwrite (https://appwrite.io) and individual contributors.
|
||||
$licenseContent = 'Copyright (c) '.date('Y').' Appwrite (https://appwrite.io) and individual contributors.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
@@ -124,7 +125,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
$config = new Node();
|
||||
$config->setNPMPackage('node-appwrite');
|
||||
$config->setBowerPackage('appwrite');
|
||||
$warning = $warning . "\n\n > This is the Node.js SDK for integrating with Appwrite from your Node.js server-side code.
|
||||
$warning = $warning."\n\n > This is the Node.js SDK for integrating with Appwrite from your Node.js server-side code.
|
||||
If you're looking to integrate from the browser, you should check [appwrite/sdk-for-web](https://github.com/appwrite/sdk-for-web)";
|
||||
break;
|
||||
case 'deno':
|
||||
@@ -150,14 +151,14 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
case 'dart':
|
||||
$config = new Dart();
|
||||
$config->setPackageName('dart_appwrite');
|
||||
$warning = $warning . "\n\n > This is the Dart SDK for integrating with Appwrite from your Dart server-side code. If you're looking for the Flutter SDK you should check [appwrite/sdk-for-flutter](https://github.com/appwrite/sdk-for-flutter)";
|
||||
$warning = $warning."\n\n > This is the Dart SDK for integrating with Appwrite from your Dart server-side code. If you're looking for the Flutter SDK you should check [appwrite/sdk-for-flutter](https://github.com/appwrite/sdk-for-flutter)";
|
||||
break;
|
||||
case 'go':
|
||||
$config = new Go();
|
||||
break;
|
||||
case 'swift':
|
||||
$config = new Swift();
|
||||
$warning = $warning . "\n\n > This is the Swift SDK for integrating with Appwrite from your Swift server-side code. If you're looking for the Apple SDK you should check [appwrite/sdk-for-apple](https://github.com/appwrite/sdk-for-apple)";
|
||||
$warning = $warning."\n\n > This is the Swift SDK for integrating with Appwrite from your Swift server-side code. If you're looking for the Apple SDK you should check [appwrite/sdk-for-apple](https://github.com/appwrite/sdk-for-apple)";
|
||||
break;
|
||||
case 'apple':
|
||||
$config = new Apple();
|
||||
@@ -171,7 +172,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
break;
|
||||
case 'kotlin':
|
||||
$config = new Kotlin();
|
||||
$warning = $warning . "\n\n > This is the Kotlin SDK for integrating with Appwrite from your Kotlin server-side code. If you're looking for the Android SDK you should check [appwrite/sdk-for-android](https://github.com/appwrite/sdk-for-android)";
|
||||
$warning = $warning."\n\n > This is the Kotlin SDK for integrating with Appwrite from your Kotlin server-side code. If you're looking for the Android SDK you should check [appwrite/sdk-for-android](https://github.com/appwrite/sdk-for-android)";
|
||||
break;
|
||||
case 'graphql':
|
||||
$config = new GraphQL();
|
||||
@@ -180,7 +181,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
$config = new REST();
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Language "' . $language['key'] . '" not supported');
|
||||
throw new Exception('Language "'.$language['key'].'" not supported');
|
||||
}
|
||||
|
||||
Console::info("Generating {$language['name']} SDK...");
|
||||
@@ -228,29 +229,28 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
$gitUrl = $language['gitUrl'];
|
||||
$gitBranch = $language['gitBranch'];
|
||||
|
||||
|
||||
if (!$production) {
|
||||
$gitUrl = 'git@github.com:aw-tests/' . $language['gitRepoName'] . '.git';
|
||||
if (! $production) {
|
||||
$gitUrl = 'git@github.com:aw-tests/'.$language['gitRepoName'].'.git';
|
||||
}
|
||||
|
||||
if ($git && !empty($gitUrl)) {
|
||||
\exec('rm -rf ' . $target . ' && \
|
||||
mkdir -p ' . $target . ' && \
|
||||
cd ' . $target . ' && \
|
||||
git init --initial-branch=' . $gitBranch . ' && \
|
||||
git remote add origin ' . $gitUrl . ' && \
|
||||
if ($git && ! empty($gitUrl)) {
|
||||
\exec('rm -rf '.$target.' && \
|
||||
mkdir -p '.$target.' && \
|
||||
cd '.$target.' && \
|
||||
git init --initial-branch='.$gitBranch.' && \
|
||||
git remote add origin '.$gitUrl.' && \
|
||||
git fetch && \
|
||||
git pull ' . $gitUrl . ' && \
|
||||
rm -rf ' . $target . '/* && \
|
||||
cp -r ' . $result . '/* ' . $target . '/ && \
|
||||
git pull '.$gitUrl.' && \
|
||||
rm -rf '.$target.'/* && \
|
||||
cp -r '.$result.'/* '.$target.'/ && \
|
||||
git add . && \
|
||||
git commit -m "' . $message . '" && \
|
||||
git push -u origin ' . $gitBranch . '
|
||||
git commit -m "'.$message.'" && \
|
||||
git push -u origin '.$gitBranch.'
|
||||
');
|
||||
|
||||
Console::success("Pushed {$language['name']} SDK to {$gitUrl}");
|
||||
|
||||
\exec('rm -rf ' . $target);
|
||||
\exec('rm -rf '.$target);
|
||||
Console::success("Remove temp directory '{$target}' for {$language['name']} SDK");
|
||||
}
|
||||
|
||||
@@ -261,10 +261,10 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
}
|
||||
|
||||
foreach ($docDirectories as $languageTitle => $path) {
|
||||
$languagePath = strtolower($languageTitle !== 0 ? '/' . $languageTitle : '');
|
||||
$languagePath = strtolower($languageTitle !== 0 ? '/'.$languageTitle : '');
|
||||
\exec(
|
||||
'mkdir -p ' . $resultExamples . $languagePath . ' && \
|
||||
cp -r ' . $result . '/docs/examples' . $languagePath . ' ' . $resultExamples
|
||||
'mkdir -p '.$resultExamples.$languagePath.' && \
|
||||
cp -r '.$result.'/docs/examples'.$languagePath.' '.$resultExamples
|
||||
);
|
||||
Console::success("Copied code examples for {$language['name']} SDK to: {$resultExamples}");
|
||||
}
|
||||
|
||||
+24
-24
@@ -2,7 +2,6 @@
|
||||
|
||||
global $cli;
|
||||
|
||||
use Utopia\Validator\Text;
|
||||
use Appwrite\Specification\Format\OpenAPI3;
|
||||
use Appwrite\Specification\Format\Swagger2;
|
||||
use Appwrite\Specification\Specification;
|
||||
@@ -12,6 +11,7 @@ use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Request;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
$cli
|
||||
@@ -155,15 +155,15 @@ $cli
|
||||
$sdkPlaforms[] = APP_PLATFORM_CLIENT;
|
||||
}
|
||||
|
||||
if (!$route->getLabel('docs', true)) {
|
||||
if (! $route->getLabel('docs', true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($route->getLabel('sdk.mock', false) && !$mocks) {
|
||||
if ($route->getLabel('sdk.mock', false) && ! $mocks) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$route->getLabel('sdk.mock', false) && $mocks) {
|
||||
if (! $route->getLabel('sdk.mock', false) && $mocks) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ $cli
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($platform !== APP_PLATFORM_CONSOLE && !\in_array($platforms[$platform], $sdkPlaforms)) {
|
||||
if ($platform !== APP_PLATFORM_CONSOLE && ! \in_array($platforms[$platform], $sdkPlaforms)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -181,10 +181,10 @@ $cli
|
||||
|
||||
foreach (Config::getParam('services', []) as $service) {
|
||||
if (
|
||||
!isset($service['docs']) // Skip service if not part of the public API
|
||||
|| !isset($service['sdk'])
|
||||
|| !$service['docs']
|
||||
|| !$service['sdk']
|
||||
! isset($service['docs']) // Skip service if not part of the public API
|
||||
|| ! isset($service['sdk'])
|
||||
|| ! $service['docs']
|
||||
|| ! $service['sdk']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ $cli
|
||||
$models = $response->getModels();
|
||||
|
||||
foreach ($models as $key => $value) {
|
||||
if ($platform !== APP_PLATFORM_CONSOLE && !$value->isPublic()) {
|
||||
if ($platform !== APP_PLATFORM_CONSOLE && ! $value->isPublic()) {
|
||||
unset($models[$key]);
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ $cli
|
||||
$formatInstance = match ($format) {
|
||||
'swagger2' => new Swagger2(...$arguments),
|
||||
'open-api3' => new OpenAPI3(...$arguments),
|
||||
default => throw new Exception('Format not found: ' . $format)
|
||||
default => throw new Exception('Format not found: '.$format)
|
||||
};
|
||||
|
||||
$specs = new Specification($formatInstance);
|
||||
@@ -221,36 +221,36 @@ $cli
|
||||
->setParam('description', 'Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)')
|
||||
->setParam('endpoint', 'https://HOSTNAME/v1')
|
||||
->setParam('version', APP_VERSION_STABLE)
|
||||
->setParam('terms', $endpoint . '/policy/terms')
|
||||
->setParam('terms', $endpoint.'/policy/terms')
|
||||
->setParam('support.email', $email)
|
||||
->setParam('support.url', $endpoint . '/support')
|
||||
->setParam('contact.name', APP_NAME . ' Team')
|
||||
->setParam('support.url', $endpoint.'/support')
|
||||
->setParam('contact.name', APP_NAME.' Team')
|
||||
->setParam('contact.email', $email)
|
||||
->setParam('contact.url', $endpoint . '/support')
|
||||
->setParam('contact.url', $endpoint.'/support')
|
||||
->setParam('license.name', 'BSD-3-Clause')
|
||||
->setParam('license.url', 'https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE')
|
||||
->setParam('docs.description', 'Full API docs, specs and tutorials')
|
||||
->setParam('docs.url', $endpoint . '/docs');
|
||||
->setParam('docs.url', $endpoint.'/docs');
|
||||
|
||||
if ($mocks) {
|
||||
$path = __DIR__ . '/../config/specs/' . $format . '-mocks-' . $platform . '.json';
|
||||
$path = __DIR__.'/../config/specs/'.$format.'-mocks-'.$platform.'.json';
|
||||
|
||||
if (!file_put_contents($path, json_encode($specs->parse()))) {
|
||||
throw new Exception('Failed to save mocks spec file: ' . $path);
|
||||
if (! file_put_contents($path, json_encode($specs->parse()))) {
|
||||
throw new Exception('Failed to save mocks spec file: '.$path);
|
||||
}
|
||||
|
||||
Console::success('Saved mocks spec file: ' . realpath($path));
|
||||
Console::success('Saved mocks spec file: '.realpath($path));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = __DIR__ . '/../config/specs/' . $format . '-' . $version . '-' . $platform . '.json';
|
||||
$path = __DIR__.'/../config/specs/'.$format.'-'.$version.'-'.$platform.'.json';
|
||||
|
||||
if (!file_put_contents($path, json_encode($specs->parse()))) {
|
||||
throw new Exception('Failed to save spec file: ' . $path);
|
||||
if (! file_put_contents($path, json_encode($specs->parse()))) {
|
||||
throw new Exception('Failed to save spec file: '.$path);
|
||||
}
|
||||
|
||||
Console::success('Saved spec file: ' . realpath($path));
|
||||
Console::success('Saved spec file: '.realpath($path));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+2
-2
@@ -13,11 +13,11 @@ $cli
|
||||
->desc('Validate server certificates')
|
||||
->param('domain', App::getEnv('_APP_DOMAIN', ''), new Hostname(), 'Domain to generate certificate for. If empty, main domain will be used.', true)
|
||||
->action(function ($domain) {
|
||||
Console::success('Scheduling a job to issue a TLS certificate for domain: ' . $domain);
|
||||
Console::success('Scheduling a job to issue a TLS certificate for domain: '.$domain);
|
||||
|
||||
(new Certificate())
|
||||
->setDomain(new Document([
|
||||
'domain' => $domain
|
||||
'domain' => $domain,
|
||||
]))
|
||||
->setSkipRenewCheck(true)
|
||||
->trigger();
|
||||
|
||||
+7
-7
@@ -11,9 +11,8 @@ use Utopia\CLI\Console;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Database as UtopiaDatabase;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Registry\Registry;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Registry\Registry;
|
||||
|
||||
Authorization::disable();
|
||||
Authorization::setDefaultStatus(false);
|
||||
@@ -34,14 +33,14 @@ function getDatabase(Registry &$register, string $namespace): UtopiaDatabase
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace($namespace);
|
||||
|
||||
if (!$database->exists($database->getDefaultDatabase(), 'projects')) {
|
||||
if (! $database->exists($database->getDefaultDatabase(), 'projects')) {
|
||||
throw new Exception('Projects collection not ready');
|
||||
}
|
||||
break; // leave loop if successful
|
||||
} 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(DATABASE_RECONNECT_SLEEP);
|
||||
}
|
||||
@@ -73,6 +72,7 @@ function getInfluxDB(Registry &$register): InfluxDatabase
|
||||
sleep($sleep);
|
||||
}
|
||||
} while ($attempts < $max);
|
||||
|
||||
return $database;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ $logError = function (Throwable $error, string $action = 'syncUsageStats') use (
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
$log = new Log();
|
||||
$log->setNamespace("usage");
|
||||
$log->setNamespace('usage');
|
||||
$log->setServer(\gethostname());
|
||||
$log->setVersion($version);
|
||||
$log->setType(Log::TYPE_ERROR);
|
||||
@@ -103,7 +103,7 @@ $logError = function (Throwable $error, string $action = 'syncUsageStats') use (
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Usage stats log pushed with status code: ' . $responseCode);
|
||||
Console::info('Usage stats log pushed with status code: '.$responseCode);
|
||||
}
|
||||
|
||||
Console::warning("Failed: {$error->getMessage()}");
|
||||
@@ -115,7 +115,7 @@ $cli
|
||||
->desc('Schedules syncing data from influxdb to Appwrite console db')
|
||||
->action(function () use ($register, $logError) {
|
||||
Console::title('Usage Aggregation V1');
|
||||
Console::success(APP_NAME . ' usage aggregation process v1 has started');
|
||||
Console::success(APP_NAME.' usage aggregation process v1 has started');
|
||||
|
||||
$database = getDatabase($register, '_console');
|
||||
$influxDB = getInfluxDB($register);
|
||||
|
||||
+1
-1
@@ -20,6 +20,6 @@ $cli
|
||||
}
|
||||
|
||||
foreach ($vars as $key => $value) {
|
||||
Console::log('- ' . $value['name'] . '=' . App::getEnv($value['name'], ''));
|
||||
Console::log('- '.$value['name'].'='.App::getEnv($value['name'], ''));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,16 +6,16 @@ use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Audits V1 Worker');
|
||||
Console::success(APP_NAME . ' audits worker v1 has started');
|
||||
Console::success(APP_NAME.' audits worker v1 has started');
|
||||
|
||||
class AuditsV1 extends Worker
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return "audits";
|
||||
return 'audits';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
|
||||
+16
-17
@@ -3,24 +3,22 @@
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Appwrite\Usage\Stats;
|
||||
use Appwrite\Utopia\Response\Model\Deployment;
|
||||
use Cron\CronExpression;
|
||||
use Executor\Executor;
|
||||
use Appwrite\Usage\Stats;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Builds V1 Worker');
|
||||
Console::success(APP_NAME . ' build worker v1 has started');
|
||||
Console::success(APP_NAME.' build worker v1 has started');
|
||||
|
||||
// TODO: Executor should return appropriate response codes.
|
||||
class BuildsV1 extends Worker
|
||||
@@ -29,7 +27,7 @@ class BuildsV1 extends Worker
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "builds";
|
||||
return 'builds';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -47,7 +45,7 @@ class BuildsV1 extends Worker
|
||||
switch ($type) {
|
||||
case BUILD_TYPE_DEPLOYMENT:
|
||||
case BUILD_TYPE_RETRY:
|
||||
Console::info('Creating build for deployment: ' . $deployment->getId());
|
||||
Console::info('Creating build for deployment: '.$deployment->getId());
|
||||
$this->buildDeployment($project, $resource, $deployment);
|
||||
break;
|
||||
|
||||
@@ -75,7 +73,7 @@ class BuildsV1 extends Worker
|
||||
$key = $function->getAttribute('runtime');
|
||||
$runtime = isset($runtimes[$key]) ? $runtimes[$key] : null;
|
||||
if (\is_null($runtime)) {
|
||||
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||
throw new Exception('Runtime "'.$function->getAttribute('runtime', '').'" is not supported');
|
||||
}
|
||||
|
||||
$buildId = $deployment->getAttribute('buildId', '');
|
||||
@@ -95,7 +93,7 @@ class BuildsV1 extends Worker
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'endTime' => null,
|
||||
'duration' => 0
|
||||
'duration' => 0,
|
||||
]));
|
||||
$deployment->setAttribute('buildId', $buildId);
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
|
||||
@@ -128,7 +126,7 @@ class BuildsV1 extends Worker
|
||||
/** Trigger Realtime */
|
||||
$allEvents = Event::generateEvents('functions.[functionId].deployments.[deploymentId].update', [
|
||||
'functionId' => $function->getId(),
|
||||
'deploymentId' => $deployment->getId()
|
||||
'deploymentId' => $deployment->getId(),
|
||||
]);
|
||||
$target = Realtime::fromPayload(
|
||||
// Pass first, most verbose event pattern
|
||||
@@ -149,6 +147,7 @@ class BuildsV1 extends Worker
|
||||
|
||||
$vars = array_reduce($function['vars'] ?? [], function (array $carry, Document $var) {
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value');
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
@@ -160,7 +159,7 @@ class BuildsV1 extends Worker
|
||||
deploymentId: $deployment->getId(),
|
||||
entrypoint: $deployment->getAttribute('entrypoint'),
|
||||
source: $source,
|
||||
destination: APP_STORAGE_BUILDS . "/app-{$project->getId()}",
|
||||
destination: APP_STORAGE_BUILDS."/app-{$project->getId()}",
|
||||
vars: $vars,
|
||||
runtime: $key,
|
||||
baseImage: $baseImage,
|
||||
@@ -169,7 +168,7 @@ class BuildsV1 extends Worker
|
||||
commands: [
|
||||
'sh', '-c',
|
||||
'tar -zxf /tmp/code.tar.gz -C /usr/code && \
|
||||
cd /usr/local/src/ && ./build.sh'
|
||||
cd /usr/local/src/ && ./build.sh',
|
||||
]
|
||||
);
|
||||
|
||||
@@ -194,8 +193,8 @@ class BuildsV1 extends Worker
|
||||
|
||||
/** Update function schedule */
|
||||
$schedule = $function->getAttribute('schedule', '');
|
||||
$cron = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
$cron = (empty($function->getAttribute('deployment')) && ! empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (empty($function->getAttribute('deployment')) && ! empty($schedule)) ? DateTime::format($cron->getNextRunDate()) : null;
|
||||
$function->setAttribute('scheduleNext', $next);
|
||||
$function = $dbForProject->updateDocument('functions', $function->getId(), $function);
|
||||
} catch (\Throwable $th) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Network\Validator\CNAME;
|
||||
use Appwrite\Resque\Worker;
|
||||
@@ -8,17 +7,17 @@ use Appwrite\Template\Template;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Locale\Locale;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Certificates V1 Worker');
|
||||
Console::success(APP_NAME . ' certificates worker v1 has started');
|
||||
Console::success(APP_NAME.' certificates worker v1 has started');
|
||||
|
||||
class CertificatesV1 extends Worker
|
||||
{
|
||||
@@ -31,7 +30,7 @@ class CertificatesV1 extends Worker
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "certificates";
|
||||
return 'certificates';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -69,7 +68,6 @@ class CertificatesV1 extends Worker
|
||||
*
|
||||
* Note: Renewals are checked and scheduled from maintenence worker
|
||||
*/
|
||||
|
||||
$this->dbForConsole = $this->getConsoleDB();
|
||||
|
||||
$skipCheck = $this->args['skipRenewCheck'] ?? false; // If true, we won't double-check expiry from cert file
|
||||
@@ -80,7 +78,7 @@ class CertificatesV1 extends Worker
|
||||
$certificate = $this->dbForConsole->findOne('certificates', [Query::equal('domain', [$domain->get()])]);
|
||||
|
||||
// If we don't have certificate for domain yet, let's create new document. At the end we save it
|
||||
if (!$certificate) {
|
||||
if (! $certificate) {
|
||||
$certificate = new Document();
|
||||
$certificate->setAttribute('domain', $domain->get());
|
||||
}
|
||||
@@ -93,14 +91,14 @@ class CertificatesV1 extends Worker
|
||||
}
|
||||
|
||||
// Validate domain and DNS records. Skip if job is forced
|
||||
if (!$skipCheck) {
|
||||
if (! $skipCheck) {
|
||||
$mainDomain = $this->getMainDomain();
|
||||
$isMainDomain = !isset($mainDomain) || $domain->get() === $mainDomain;
|
||||
$isMainDomain = ! isset($mainDomain) || $domain->get() === $mainDomain;
|
||||
$this->validateDomain($domain, $isMainDomain);
|
||||
}
|
||||
|
||||
// If certificate exists already, double-check expiry date. Skip if job is forced
|
||||
if (!$skipCheck && !$this->isRenewRequired($domain->get())) {
|
||||
if (! $skipCheck && ! $this->isRenewRequired($domain->get())) {
|
||||
throw new Exception('Renew isn\'t required.');
|
||||
}
|
||||
|
||||
@@ -153,16 +151,15 @@ class CertificatesV1 extends Worker
|
||||
/**
|
||||
* Save certificate data into database.
|
||||
*
|
||||
* @param string $domain Domain name that certificate is for
|
||||
* @param Document $certificate Certificate document that we need to save
|
||||
*
|
||||
* @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
|
||||
{
|
||||
// Check if update or insert required
|
||||
$certificateDocument = $this->dbForConsole->findOne('certificates', [Query::equal('domain', [$domain])]);
|
||||
if (!empty($certificateDocument) && !$certificateDocument->isEmpty()) {
|
||||
if (! empty($certificateDocument) && ! $certificateDocument->isEmpty()) {
|
||||
// Merge new data with current data
|
||||
$certificate = new Document(\array_merge($certificateDocument->getArrayCopy(), $certificate->getArrayCopy()));
|
||||
|
||||
@@ -183,7 +180,7 @@ class CertificatesV1 extends Worker
|
||||
private function getMainDomain(): ?string
|
||||
{
|
||||
$envDomain = App::getEnv('_APP_DOMAIN', '');
|
||||
if (!empty($envDomain) && $envDomain !== 'localhost') {
|
||||
if (! empty($envDomain) && $envDomain !== 'localhost') {
|
||||
return $envDomain;
|
||||
} else {
|
||||
$domainDocument = $this->dbForConsole->findOne('domains', [Query::orderAsc('_id')]);
|
||||
@@ -200,9 +197,8 @@ class CertificatesV1 extends Worker
|
||||
* - Domain needs to be public and valid (prevents NFT domains that are not supported by Let's Encrypt)
|
||||
* - Domain must have proper DNS record
|
||||
*
|
||||
* @param Domain $domain Domain which we validate
|
||||
* @param bool $isMainDomain In case of master domain, we look for different DNS configurations
|
||||
*
|
||||
* @param Domain $domain Domain which we validate
|
||||
* @param bool $isMainDomain In case of master domain, we look for different DNS configurations
|
||||
* @return void
|
||||
*/
|
||||
private function validateDomain(Domain $domain, bool $isMainDomain): void
|
||||
@@ -211,23 +207,23 @@ class CertificatesV1 extends Worker
|
||||
throw new Exception('Missing certificate domain.');
|
||||
}
|
||||
|
||||
if (!$domain->isKnown() || $domain->isTest()) {
|
||||
if (! $domain->isKnown() || $domain->isTest()) {
|
||||
throw new Exception('Unknown public suffix for domain.');
|
||||
}
|
||||
|
||||
if (!$isMainDomain) {
|
||||
if (! $isMainDomain) {
|
||||
// TODO: Would be awesome to also support A/AAAA records here. Maybe dry run?
|
||||
|
||||
// Validate if domain target is properly configured
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
if (!$target->isKnown() || $target->isTest()) {
|
||||
throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.');
|
||||
if (! $target->isKnown() || $target->isTest()) {
|
||||
throw new Exception('Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.');
|
||||
}
|
||||
|
||||
// Verify domain with DNS records
|
||||
$validator = new CNAME($target->get());
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
if (! $validator->isValid($domain->get())) {
|
||||
throw new Exception('Failed to verify domain DNS records.');
|
||||
}
|
||||
} else {
|
||||
@@ -239,13 +235,12 @@ class CertificatesV1 extends Worker
|
||||
/**
|
||||
* Reads expiry date of certificate from file and decides if renewal is required or not.
|
||||
*
|
||||
* @param string $domain Domain for which we check certificate file
|
||||
*
|
||||
* @param string $domain Domain for which we check certificate file
|
||||
* @return bool True, if certificate needs to be renewed
|
||||
*/
|
||||
private function isRenewRequired(string $domain): bool
|
||||
{
|
||||
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
|
||||
$certPath = APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem';
|
||||
if (\file_exists($certPath)) {
|
||||
$validTo = null;
|
||||
|
||||
@@ -269,9 +264,8 @@ class CertificatesV1 extends Worker
|
||||
/**
|
||||
* LetsEncrypt communication to issue certificate (using certbot CLI)
|
||||
*
|
||||
* @param string $folder Folder into which certificates should be generated
|
||||
* @param string $domain Domain to generate certificate for
|
||||
*
|
||||
* @param string $folder Folder into which certificates should be generated
|
||||
* @param string $domain Domain to generate certificate for
|
||||
* @return array Named array with keys 'stdout' and 'stderr', both string
|
||||
*/
|
||||
private function issueCertificate(string $folder, string $domain, string $email): array
|
||||
@@ -281,83 +275,82 @@ class CertificatesV1 extends Worker
|
||||
|
||||
$staging = (App::isProduction()) ? '' : ' --dry-run';
|
||||
$exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}"
|
||||
. " --email " . $email
|
||||
. " --cert-name " . $folder
|
||||
. " -w " . APP_STORAGE_CERTIFICATES
|
||||
. " -d {$domain}", '', $stdout, $stderr);
|
||||
.' --email '.$email
|
||||
.' --cert-name '.$folder
|
||||
.' -w '.APP_STORAGE_CERTIFICATES
|
||||
." -d {$domain}", '', $stdout, $stderr);
|
||||
|
||||
// Unexpected error, usually 5XX, API limits, ...
|
||||
if ($exit !== 0) {
|
||||
throw new Exception('Failed to issue a certificate with message: ' . $stderr);
|
||||
throw new Exception('Failed to issue a certificate with message: '.$stderr);
|
||||
}
|
||||
|
||||
return [
|
||||
'stdout' => $stdout,
|
||||
'stderr' => $stderr
|
||||
'stderr' => $stderr,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read new renew date from certificate file generated by Let's Encrypt
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
* @return string
|
||||
*/
|
||||
private function getRenewDate(string $domain): string
|
||||
{
|
||||
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
|
||||
$certPath = APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem';
|
||||
$certData = openssl_x509_parse(file_get_contents($certPath));
|
||||
$validTo = $certData['validTo_time_t'] ?? null;
|
||||
$dt = (new \DateTime())->setTimestamp($validTo);
|
||||
|
||||
return DateTime::addSeconds($dt, -60 * 60 * 24 * 30); // -30 days
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to take files from Let's Encrypt, and put it into Traefik.
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
* @param string $folder Folder in which certificates were generated
|
||||
* @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
* @param string $folder Folder in which certificates were generated
|
||||
* @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error
|
||||
* @return void
|
||||
*/
|
||||
private function applyCertificateFiles(string $folder, string $domain, array $letsEncryptData): void
|
||||
{
|
||||
// Prepare folder in storage for domain
|
||||
$path = APP_STORAGE_CERTIFICATES . '/' . $domain;
|
||||
if (!\is_readable($path)) {
|
||||
if (!\mkdir($path, 0755, true)) {
|
||||
$path = APP_STORAGE_CERTIFICATES.'/'.$domain;
|
||||
if (! \is_readable($path)) {
|
||||
if (! \mkdir($path, 0755, true)) {
|
||||
throw new Exception('Failed to create path for certificate.');
|
||||
}
|
||||
}
|
||||
|
||||
// Move generated files
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $folder . '/cert.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem')) {
|
||||
throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
if (! @\rename('/etc/letsencrypt/live/'.$folder.'/cert.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem')) {
|
||||
throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $folder . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/chain.pem')) {
|
||||
throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
if (! @\rename('/etc/letsencrypt/live/'.$folder.'/chain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/chain.pem')) {
|
||||
throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $folder . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/fullchain.pem')) {
|
||||
throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
if (! @\rename('/etc/letsencrypt/live/'.$folder.'/fullchain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/fullchain.pem')) {
|
||||
throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $folder . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/privkey.pem')) {
|
||||
throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
if (! @\rename('/etc/letsencrypt/live/'.$folder.'/privkey.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/privkey.pem')) {
|
||||
throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
$config = \implode(PHP_EOL, [
|
||||
"tls:",
|
||||
" certificates:",
|
||||
'tls:',
|
||||
' certificates:',
|
||||
" - certFile: /storage/certificates/{$domain}/fullchain.pem",
|
||||
" keyFile: /storage/certificates/{$domain}/privkey.pem"
|
||||
" keyFile: /storage/certificates/{$domain}/privkey.pem",
|
||||
]);
|
||||
|
||||
// Save configuration into Traefik using our new cert files
|
||||
if (!\file_put_contents(APP_STORAGE_CONFIG . '/' . $domain . '.yml', $config)) {
|
||||
if (! \file_put_contents(APP_STORAGE_CONFIG.'/'.$domain.'.yml', $config)) {
|
||||
throw new Exception('Failed to save Traefik configuration.');
|
||||
}
|
||||
}
|
||||
@@ -365,39 +358,38 @@ class CertificatesV1 extends Worker
|
||||
/**
|
||||
* Method to make sure information about error is delivered to admnistrator.
|
||||
*
|
||||
* @param string $domain Domain that caused the error
|
||||
* @param string $errorMessage Verbose error message
|
||||
* @param int $attempt How many times it failed already
|
||||
*
|
||||
* @param string $domain Domain that caused the error
|
||||
* @param string $errorMessage Verbose error message
|
||||
* @param int $attempt How many times it failed already
|
||||
* @return void
|
||||
*/
|
||||
private function notifyError(string $domain, string $errorMessage, int $attempt): void
|
||||
{
|
||||
// Log error into console
|
||||
Console::warning('Cannot renew domain (' . $domain . ') on attempt no. ' . $attempt . ' certificate: ' . $errorMessage);
|
||||
Console::warning('Cannot renew domain ('.$domain.') on attempt no. '.$attempt.' certificate: '.$errorMessage);
|
||||
|
||||
// Send mail to administratore mail
|
||||
|
||||
$locale = new Locale(App::getEnv('_APP_LOCALE', 'en'));
|
||||
if (!$locale->getText('emails.sender') || !$locale->getText("emails.certificate.hello") || !$locale->getText("emails.certificate.subject") || !$locale->getText("emails.certificate.body") || !$locale->getText("emails.certificate.footer") || !$locale->getText("emails.certificate.thanks") || !$locale->getText("emails.certificate.signature")) {
|
||||
if (! $locale->getText('emails.sender') || ! $locale->getText('emails.certificate.hello') || ! $locale->getText('emails.certificate.subject') || ! $locale->getText('emails.certificate.body') || ! $locale->getText('emails.certificate.footer') || ! $locale->getText('emails.certificate.thanks') || ! $locale->getText('emails.certificate.signature')) {
|
||||
$locale->setDefault('en');
|
||||
}
|
||||
|
||||
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
|
||||
$body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl');
|
||||
|
||||
$subject = \sprintf($locale->getText("emails.certificate.subject"), $domain);
|
||||
$body->setParam('{{domain}}', $domain);
|
||||
$body->setParam('{{error}}', $errorMessage);
|
||||
$body->setParam('{{attempt}}', $attempt);
|
||||
$subject = \sprintf($locale->getText('emails.certificate.subject'), $domain);
|
||||
$body->setParam('{{domain}}', $domain);
|
||||
$body->setParam('{{error}}', $errorMessage);
|
||||
$body->setParam('{{attempt}}', $attempt);
|
||||
|
||||
$body
|
||||
->setParam('{{subject}}', $subject)
|
||||
->setParam('{{hello}}', $locale->getText("emails.certificate.hello"))
|
||||
->setParam('{{body}}', $locale->getText("emails.certificate.body"))
|
||||
->setParam('{{redirect}}', 'https://' . $domain)
|
||||
->setParam('{{footer}}', $locale->getText("emails.certificate.footer"))
|
||||
->setParam('{{thanks}}', $locale->getText("emails.certificate.thanks"))
|
||||
->setParam('{{signature}}', $locale->getText("emails.certificate.signature"))
|
||||
->setParam('{{hello}}', $locale->getText('emails.certificate.hello'))
|
||||
->setParam('{{body}}', $locale->getText('emails.certificate.body'))
|
||||
->setParam('{{redirect}}', 'https://'.$domain)
|
||||
->setParam('{{footer}}', $locale->getText('emails.certificate.footer'))
|
||||
->setParam('{{thanks}}', $locale->getText('emails.certificate.thanks'))
|
||||
->setParam('{{signature}}', $locale->getText('emails.certificate.signature'))
|
||||
->setParam('{{project}}', 'Console')
|
||||
->setParam('{{direction}}', $locale->getText('settings.direction'))
|
||||
->setParam('{{bg-body}}', '#f7f7f7')
|
||||
@@ -419,9 +411,8 @@ class CertificatesV1 extends Worker
|
||||
* - when renew creates new document? It might?
|
||||
* - overall makes it more reliable
|
||||
*
|
||||
* @param string $certificateId ID of a new or updated certificate document
|
||||
* @param string $domain Domain that is affected by new certificate
|
||||
*
|
||||
* @param string $certificateId ID of a new or updated certificate document
|
||||
* @param string $domain Domain that is affected by new certificate
|
||||
* @return void
|
||||
*/
|
||||
private function updateDomainDocuments(string $certificateId, string $domain): void
|
||||
|
||||
+37
-38
@@ -6,10 +6,10 @@ use Appwrite\Resque\Worker;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
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
|
||||
{
|
||||
@@ -48,7 +48,7 @@ class DatabaseV1 extends Worker
|
||||
break;
|
||||
|
||||
default:
|
||||
Console::error('No database operation for type: ' . $type);
|
||||
Console::error('No database operation for type: '.$type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -58,10 +58,10 @@ class DatabaseV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param string $projectId
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function createAttribute(Document $database, Document $collection, Document $attribute, string $projectId): void
|
||||
{
|
||||
@@ -71,7 +71,7 @@ class DatabaseV1 extends Worker
|
||||
$events = Event::generateEvents('databases.[databaseId].collections.[collectionId].attributes.[attributeId].update', [
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId(),
|
||||
'attributeId' => $attribute->getId()
|
||||
'attributeId' => $attribute->getId(),
|
||||
]);
|
||||
/**
|
||||
* Fetch attribute from the database, since with Resque float values are loosing informations.
|
||||
@@ -92,7 +92,7 @@ class DatabaseV1 extends Worker
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
try {
|
||||
if (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
|
||||
if (! $dbForProject->createAttribute('database_'.$database->getInternalId().'_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'));
|
||||
@@ -116,19 +116,19 @@ class DatabaseV1 extends Worker
|
||||
options: [
|
||||
'projectId' => $projectId,
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId()
|
||||
'collectionId' => $collection->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param string $projectId
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteAttribute(Document $database, Document $collection, Document $attribute, string $projectId): void
|
||||
{
|
||||
@@ -138,7 +138,7 @@ class DatabaseV1 extends Worker
|
||||
$events = Event::generateEvents('databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete', [
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId(),
|
||||
'attributeId' => $attribute->getId()
|
||||
'attributeId' => $attribute->getId(),
|
||||
]);
|
||||
$collectionId = $collection->getId();
|
||||
$key = $attribute->getAttribute('key', '');
|
||||
@@ -152,7 +152,7 @@ class DatabaseV1 extends Worker
|
||||
// - failed: attribute was never created
|
||||
// - stuck: attribute was available but cannot be removed
|
||||
try {
|
||||
if ($status !== 'failed' && !$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
|
||||
if ($status !== 'failed' && ! $dbForProject->deleteAttribute('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) {
|
||||
throw new Exception('Failed to delete Attribute');
|
||||
}
|
||||
$dbForProject->deleteDocument('attributes', $attribute->getId());
|
||||
@@ -176,7 +176,7 @@ class DatabaseV1 extends Worker
|
||||
options: [
|
||||
'projectId' => $projectId,
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId()
|
||||
'collectionId' => $collection->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -208,8 +208,7 @@ class DatabaseV1 extends Worker
|
||||
$index
|
||||
->setAttribute('attributes', $attributes, Document::SET_TYPE_ASSIGN)
|
||||
->setAttribute('lengths', $lengths, Document::SET_TYPE_ASSIGN)
|
||||
->setAttribute('orders', $orders, Document::SET_TYPE_ASSIGN)
|
||||
;
|
||||
->setAttribute('orders', $orders, Document::SET_TYPE_ASSIGN);
|
||||
|
||||
// Check if an index exists with the same attributes and orders
|
||||
$exists = false;
|
||||
@@ -233,15 +232,15 @@ class DatabaseV1 extends Worker
|
||||
}
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param string $projectId
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function createIndex(Document $database, Document $collection, Document $index, string $projectId): void
|
||||
{
|
||||
@@ -251,7 +250,7 @@ class DatabaseV1 extends Worker
|
||||
$events = Event::generateEvents('databases.[databaseId].collections.[collectionId].indexes.[indexId].update', [
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId(),
|
||||
'indexId' => $index->getId()
|
||||
'indexId' => $index->getId(),
|
||||
]);
|
||||
$collectionId = $collection->getId();
|
||||
$key = $index->getAttribute('key', '');
|
||||
@@ -262,7 +261,7 @@ class DatabaseV1 extends Worker
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
try {
|
||||
if (!$dbForProject->createIndex('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) {
|
||||
if (! $dbForProject->createIndex('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) {
|
||||
throw new Exception('Failed to create Index');
|
||||
}
|
||||
$dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available'));
|
||||
@@ -286,19 +285,19 @@ class DatabaseV1 extends Worker
|
||||
options: [
|
||||
'projectId' => $projectId,
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId()
|
||||
'collectionId' => $collection->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param string $projectId
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteIndex(Document $database, Document $collection, Document $index, string $projectId): void
|
||||
{
|
||||
@@ -308,14 +307,14 @@ class DatabaseV1 extends Worker
|
||||
$events = Event::generateEvents('databases.[databaseId].collections.[collectionId].indexes.[indexId].delete', [
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId(),
|
||||
'indexId' => $index->getId()
|
||||
'indexId' => $index->getId(),
|
||||
]);
|
||||
$key = $index->getAttribute('key');
|
||||
$status = $index->getAttribute('status', '');
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
try {
|
||||
if ($status !== 'failed' && !$dbForProject->deleteIndex('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
|
||||
if ($status !== 'failed' && ! $dbForProject->deleteIndex('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) {
|
||||
throw new Exception('Failed to delete index');
|
||||
}
|
||||
$dbForProject->deleteDocument('indexes', $index->getId());
|
||||
@@ -339,11 +338,11 @@ class DatabaseV1 extends Worker
|
||||
options: [
|
||||
'projectId' => $projectId,
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId()
|
||||
'collectionId' => $collection->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collection->getId());
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collection->getId());
|
||||
}
|
||||
}
|
||||
|
||||
+124
-110
@@ -1,31 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Executor\Executor;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Deletes V1 Worker');
|
||||
Console::success(APP_NAME . ' deletes worker v1 has started' . "\n");
|
||||
Console::success(APP_NAME.' deletes worker v1 has started'."\n");
|
||||
|
||||
class DeletesV1 extends Worker
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return "deletes";
|
||||
return 'deletes';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -67,7 +66,7 @@ class DeletesV1 extends Worker
|
||||
$this->deleteCollection($document, $project->getId());
|
||||
break;
|
||||
}
|
||||
Console::error('No lazy delete operation available for document of type: ' . $document->getCollection());
|
||||
Console::error('No lazy delete operation available for document of type: '.$document->getCollection());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -78,14 +77,14 @@ class DeletesV1 extends Worker
|
||||
|
||||
case DELETE_TYPE_AUDIT:
|
||||
$datetime = $this->args['datetime'] ?? null;
|
||||
if (!empty($datetime)) {
|
||||
if (! empty($datetime)) {
|
||||
$this->deleteAuditLogs($datetime);
|
||||
}
|
||||
|
||||
$document = new Document($this->args['document'] ?? []);
|
||||
|
||||
if (!$document->isEmpty()) {
|
||||
$this->deleteAuditLogsByResource('document/' . $document->getId(), $project->getId());
|
||||
if (! $document->isEmpty()) {
|
||||
$this->deleteAuditLogsByResource('document/'.$document->getId(), $project->getId());
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -118,7 +117,7 @@ class DeletesV1 extends Worker
|
||||
$this->deleteCacheByDate();
|
||||
break;
|
||||
default:
|
||||
Console::error('No delete operation for type: ' . $type);
|
||||
Console::error('No delete operation for type: '.$type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -128,7 +127,7 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $projectId
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteCacheByResource(string $projectId): void
|
||||
{
|
||||
@@ -147,10 +146,9 @@ class DeletesV1 extends Worker
|
||||
protected function deleteCacheFiles($query): void
|
||||
{
|
||||
$this->deleteForProjectIds(function (string $projectId) use ($query) {
|
||||
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId)
|
||||
new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId)
|
||||
);
|
||||
|
||||
$this->deleteByGroup(
|
||||
@@ -158,12 +156,12 @@ class DeletesV1 extends Worker
|
||||
$query,
|
||||
$dbForProject,
|
||||
function (Document $document) use ($cache, $projectId) {
|
||||
$path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId();
|
||||
$path = APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId.DIRECTORY_SEPARATOR.$document->getId();
|
||||
|
||||
if ($cache->purge($document->getId())) {
|
||||
Console::success('Deleting cache file: ' . $path);
|
||||
Console::success('Deleting cache file: '.$path);
|
||||
} else {
|
||||
Console::error('Failed to delete cache file: ' . $path);
|
||||
Console::error('Failed to delete cache file: '.$path);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -171,8 +169,9 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document database document
|
||||
* @param string $projectId
|
||||
* @param Document $document database document
|
||||
* @param string $projectId
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteDatabase(Document $document, string $projectId): void
|
||||
@@ -181,18 +180,19 @@ class DeletesV1 extends Worker
|
||||
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
|
||||
$this->deleteByGroup('database_' . $document->getInternalId(), [], $dbForProject, function ($document) use ($projectId) {
|
||||
$this->deleteByGroup('database_'.$document->getInternalId(), [], $dbForProject, function ($document) use ($projectId) {
|
||||
$this->deleteCollection($document, $projectId);
|
||||
});
|
||||
|
||||
$dbForProject->deleteCollection('database_' . $document->getInternalId());
|
||||
$dbForProject->deleteCollection('database_'.$document->getInternalId());
|
||||
|
||||
$this->deleteAuditLogsByResource('database/' . $databaseId, $projectId);
|
||||
$this->deleteAuditLogsByResource('database/'.$databaseId, $projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document teams document
|
||||
* @param string $projectId
|
||||
* @param Document $document teams document
|
||||
* @param string $projectId
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteCollection(Document $document, string $projectId): void
|
||||
@@ -203,23 +203,24 @@ class DeletesV1 extends Worker
|
||||
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
|
||||
$dbForProject->deleteCollection('database_' . $databaseInternalId . '_collection_' . $document->getInternalId());
|
||||
$dbForProject->deleteCollection('database_'.$databaseInternalId.'_collection_'.$document->getInternalId());
|
||||
|
||||
$this->deleteByGroup('attributes', [
|
||||
Query::equal('databaseId', [$databaseId]),
|
||||
Query::equal('collectionId', [$collectionId])
|
||||
Query::equal('collectionId', [$collectionId]),
|
||||
], $dbForProject);
|
||||
|
||||
$this->deleteByGroup('indexes', [
|
||||
Query::equal('databaseId', [$databaseId]),
|
||||
Query::equal('collectionId', [$collectionId])
|
||||
Query::equal('collectionId', [$collectionId]),
|
||||
], $dbForProject);
|
||||
|
||||
$this->deleteAuditLogsByResource('database/' . $databaseId . '/collection/' . $collectionId, $projectId);
|
||||
$this->deleteAuditLogsByResource('database/'.$databaseId.'/collection/'.$collectionId, $projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hourlyUsageRetentionDatetime
|
||||
* @param string $hourlyUsageRetentionDatetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteUsageStats(string $hourlyUsageRetentionDatetime)
|
||||
@@ -234,8 +235,9 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document teams document
|
||||
* @param string $projectId
|
||||
* @param Document $document teams document
|
||||
* @param string $projectId
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteMemberships(Document $document, string $projectId): void
|
||||
@@ -244,12 +246,13 @@ class DeletesV1 extends Worker
|
||||
|
||||
// Delete Memberships
|
||||
$this->deleteByGroup('memberships', [
|
||||
Query::equal('teamId', [$teamId])
|
||||
Query::equal('teamId', [$teamId]),
|
||||
], $this->getProjectDB($projectId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document project document
|
||||
* @param Document $document project document
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteProject(Document $document): void
|
||||
@@ -260,7 +263,7 @@ class DeletesV1 extends Worker
|
||||
$dbForConsole = $this->getConsoleDB();
|
||||
|
||||
$domains = $dbForConsole->find('domains', [
|
||||
Query::equal('projectInternalId', [$document->getInternalId()])
|
||||
Query::equal('projectInternalId', [$document->getInternalId()]),
|
||||
]);
|
||||
|
||||
foreach ($domains as $domain) {
|
||||
@@ -303,8 +306,9 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document user document
|
||||
* @param string $projectId
|
||||
* @param Document $document user document
|
||||
* @param string $projectId
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteUser(Document $document, string $projectId): void
|
||||
@@ -313,20 +317,19 @@ class DeletesV1 extends Worker
|
||||
|
||||
// Delete all sessions of this user from the sessions table and update the sessions field of the user record
|
||||
$this->deleteByGroup('sessions', [
|
||||
Query::equal('userId', [$userId])
|
||||
Query::equal('userId', [$userId]),
|
||||
], $this->getProjectDB($projectId));
|
||||
|
||||
$this->getProjectDB($projectId)->deleteCachedDocument('users', $userId);
|
||||
|
||||
// Delete Memberships and decrement team membership counts
|
||||
$this->deleteByGroup('memberships', [
|
||||
Query::equal('userId', [$userId])
|
||||
Query::equal('userId', [$userId]),
|
||||
], $this->getProjectDB($projectId), function (Document $document) use ($projectId) {
|
||||
|
||||
if ($document->getAttribute('confirm')) { // Count only confirmed members
|
||||
$teamId = $document->getAttribute('teamId');
|
||||
$team = $this->getProjectDB($projectId)->getDocument('teams', $teamId);
|
||||
if (!$team->isEmpty()) {
|
||||
if (! $team->isEmpty()) {
|
||||
$team = $this
|
||||
->getProjectDB($projectId)
|
||||
->updateDocument(
|
||||
@@ -341,12 +344,13 @@ class DeletesV1 extends Worker
|
||||
|
||||
// Delete tokens
|
||||
$this->deleteByGroup('tokens', [
|
||||
Query::equal('userId', [$userId])
|
||||
Query::equal('userId', [$userId]),
|
||||
], $this->getProjectDB($projectId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datetime
|
||||
* @param string $datetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteExecutionLogs(string $datetime): void
|
||||
@@ -355,7 +359,7 @@ class DeletesV1 extends Worker
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
// Delete Executions
|
||||
$this->deleteByGroup('executions', [
|
||||
Query::lessThan('$createdAt', $datetime)
|
||||
Query::lessThan('$createdAt', $datetime),
|
||||
], $dbForProject);
|
||||
});
|
||||
}
|
||||
@@ -373,13 +377,14 @@ class DeletesV1 extends Worker
|
||||
|
||||
// Delete Sessions
|
||||
$this->deleteByGroup('sessions', [
|
||||
Query::lessThan('$createdAt', $expired)
|
||||
Query::lessThan('$createdAt', $expired),
|
||||
], $dbForProject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datetime
|
||||
* @param string $datetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteRealtimeUsage(string $datetime): void
|
||||
@@ -388,13 +393,14 @@ class DeletesV1 extends Worker
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
// Delete Dead Realtime Logs
|
||||
$this->deleteByGroup('realtime', [
|
||||
Query::lessThan('timestamp', $datetime)
|
||||
Query::lessThan('timestamp', $datetime),
|
||||
], $dbForProject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datetime
|
||||
* @param string $datetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteAbuseLogs(string $datetime): void
|
||||
@@ -405,17 +411,18 @@ class DeletesV1 extends Worker
|
||||
|
||||
$this->deleteForProjectIds(function (string $projectId) use ($datetime) {
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
$timeLimit = new TimeLimit("", 0, 1, $dbForProject);
|
||||
$timeLimit = new TimeLimit('', 0, 1, $dbForProject);
|
||||
$abuse = new Abuse($timeLimit);
|
||||
$status = $abuse->cleanup($datetime);
|
||||
if (!$status) {
|
||||
throw new Exception('Failed to delete Abuse logs for project ' . $projectId);
|
||||
if (! $status) {
|
||||
throw new Exception('Failed to delete Abuse logs for project '.$projectId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datetime
|
||||
* @param string $datetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteAuditLogs(string $datetime): void
|
||||
@@ -428,15 +435,16 @@ class DeletesV1 extends Worker
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
$audit = new Audit($dbForProject);
|
||||
$status = $audit->cleanup($datetime);
|
||||
if (!$status) {
|
||||
throw new Exception('Failed to delete Audit logs for project' . $projectId);
|
||||
if (! $status) {
|
||||
throw new Exception('Failed to delete Audit logs for project'.$projectId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $resource
|
||||
* @param string $projectId
|
||||
* @param string $resource
|
||||
* @param string $projectId
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteAuditLogsByResource(string $resource, string $projectId): void
|
||||
@@ -444,13 +452,14 @@ class DeletesV1 extends Worker
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
|
||||
$this->deleteByGroup(Audit::COLLECTION, [
|
||||
Query::equal('resource', [$resource])
|
||||
Query::equal('resource', [$resource]),
|
||||
], $dbForProject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document function document
|
||||
* @param string $projectId
|
||||
* @param Document $document function document
|
||||
* @param string $projectId
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteFunction(Document $document, string $projectId): void
|
||||
@@ -461,41 +470,41 @@ class DeletesV1 extends Worker
|
||||
/**
|
||||
* Delete Variables
|
||||
*/
|
||||
Console::info("Deleting variables for function " . $functionId);
|
||||
Console::info('Deleting variables for function '.$functionId);
|
||||
$this->deleteByGroup('variables', [
|
||||
Query::equal('functionId', [$functionId])
|
||||
Query::equal('functionId', [$functionId]),
|
||||
], $dbForProject);
|
||||
|
||||
/**
|
||||
* Delete Deployments
|
||||
*/
|
||||
Console::info("Deleting deployments for function " . $functionId);
|
||||
Console::info('Deleting deployments for function '.$functionId);
|
||||
$storageFunctions = $this->getFunctionsDevice($projectId);
|
||||
$deploymentIds = [];
|
||||
$this->deleteByGroup('deployments', [
|
||||
Query::equal('resourceId', [$functionId])
|
||||
Query::equal('resourceId', [$functionId]),
|
||||
], $dbForProject, function (Document $document) use ($storageFunctions, &$deploymentIds) {
|
||||
$deploymentIds[] = $document->getId();
|
||||
if ($storageFunctions->delete($document->getAttribute('path', ''), true)) {
|
||||
Console::success('Deleted deployment files: ' . $document->getAttribute('path', ''));
|
||||
Console::success('Deleted deployment files: '.$document->getAttribute('path', ''));
|
||||
} else {
|
||||
Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', ''));
|
||||
Console::error('Failed to delete deployment files: '.$document->getAttribute('path', ''));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Delete builds
|
||||
*/
|
||||
Console::info("Deleting builds for function " . $functionId);
|
||||
Console::info('Deleting builds for function '.$functionId);
|
||||
$storageBuilds = $this->getBuildsDevice($projectId);
|
||||
foreach ($deploymentIds as $deploymentId) {
|
||||
$this->deleteByGroup('builds', [
|
||||
Query::equal('deploymentId', [$deploymentId])
|
||||
], $dbForProject, function (Document $document) use ($storageBuilds, $deploymentId) {
|
||||
Query::equal('deploymentId', [$deploymentId]),
|
||||
], $dbForProject, function (Document $document) use ($storageBuilds) {
|
||||
if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) {
|
||||
Console::success('Deleted build files: ' . $document->getAttribute('outputPath', ''));
|
||||
Console::success('Deleted build files: '.$document->getAttribute('outputPath', ''));
|
||||
} else {
|
||||
Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', ''));
|
||||
Console::error('Failed to delete build files: '.$document->getAttribute('outputPath', ''));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -503,15 +512,15 @@ class DeletesV1 extends Worker
|
||||
/**
|
||||
* Delete Executions
|
||||
*/
|
||||
Console::info("Deleting executions for function " . $functionId);
|
||||
Console::info('Deleting executions for function '.$functionId);
|
||||
$this->deleteByGroup('executions', [
|
||||
Query::equal('functionId', [$functionId])
|
||||
Query::equal('functionId', [$functionId]),
|
||||
], $dbForProject);
|
||||
|
||||
/**
|
||||
* Request executor to delete all deployment containers
|
||||
*/
|
||||
Console::info("Requesting executor to delete all deployment containers for function " . $functionId);
|
||||
Console::info('Requesting executor to delete all deployment containers for function '.$functionId);
|
||||
$executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST'));
|
||||
foreach ($deploymentIds as $deploymentId) {
|
||||
try {
|
||||
@@ -523,8 +532,9 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document deployment document
|
||||
* @param string $projectId
|
||||
* @param Document $document deployment document
|
||||
* @param string $projectId
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteDeployment(Document $document, string $projectId): void
|
||||
@@ -536,33 +546,33 @@ class DeletesV1 extends Worker
|
||||
/**
|
||||
* Delete deployment files
|
||||
*/
|
||||
Console::info("Deleting deployment files for deployment " . $deploymentId);
|
||||
Console::info('Deleting deployment files for deployment '.$deploymentId);
|
||||
$storageFunctions = $this->getFunctionsDevice($projectId);
|
||||
if ($storageFunctions->delete($document->getAttribute('path', ''), true)) {
|
||||
Console::success('Deleted deployment files: ' . $document->getAttribute('path', ''));
|
||||
Console::success('Deleted deployment files: '.$document->getAttribute('path', ''));
|
||||
} else {
|
||||
Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', ''));
|
||||
Console::error('Failed to delete deployment files: '.$document->getAttribute('path', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete builds
|
||||
*/
|
||||
Console::info("Deleting builds for deployment " . $deploymentId);
|
||||
Console::info('Deleting builds for deployment '.$deploymentId);
|
||||
$storageBuilds = $this->getBuildsDevice($projectId);
|
||||
$this->deleteByGroup('builds', [
|
||||
Query::equal('deploymentId', [$deploymentId])
|
||||
Query::equal('deploymentId', [$deploymentId]),
|
||||
], $dbForProject, function (Document $document) use ($storageBuilds) {
|
||||
if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) {
|
||||
Console::success('Deleted build files: ' . $document->getAttribute('outputPath', ''));
|
||||
Console::success('Deleted build files: '.$document->getAttribute('outputPath', ''));
|
||||
} else {
|
||||
Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', ''));
|
||||
Console::error('Failed to delete build files: '.$document->getAttribute('outputPath', ''));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Request executor to delete the deployment container
|
||||
*/
|
||||
Console::info("Requesting executor to delete deployment container for deployment " . $deploymentId);
|
||||
Console::info('Requesting executor to delete deployment container for deployment '.$deploymentId);
|
||||
try {
|
||||
$executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST'));
|
||||
$executor->deleteRuntime($projectId, $deploymentId);
|
||||
@@ -571,19 +581,18 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Document $document to be deleted
|
||||
* @param Database $database to delete it from
|
||||
* @param callable|null $callback to perform after document is deleted
|
||||
*
|
||||
* @param Document $document to be deleted
|
||||
* @param Database $database to delete it from
|
||||
* @param callable|null $callback to perform after document is deleted
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Utopia\Database\Exception\Authorization
|
||||
*/
|
||||
protected function deleteById(Document $document, Database $database, callable $callback = null): bool
|
||||
{
|
||||
if ($database->deleteDocument($document->getCollection(), $document->getId())) {
|
||||
Console::success('Deleted document "' . $document->getId() . '" successfully');
|
||||
Console::success('Deleted document "'.$document->getId().'" successfully');
|
||||
|
||||
if (is_callable($callback)) {
|
||||
$callback($document);
|
||||
@@ -591,13 +600,15 @@ class DeletesV1 extends Worker
|
||||
|
||||
return true;
|
||||
} else {
|
||||
Console::error('Failed to delete document: ' . $document->getId());
|
||||
Console::error('Failed to delete document: '.$document->getId());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callback
|
||||
* @param callable $callback
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteForProjectIds(callable $callback): void
|
||||
@@ -620,7 +631,7 @@ class DeletesV1 extends Worker
|
||||
|
||||
$sum = count($projects);
|
||||
|
||||
Console::info('Executing delete function for chunk #' . $chunk . '. Found ' . $sum . ' projects');
|
||||
Console::info('Executing delete function for chunk #'.$chunk.'. Found '.$sum.' projects');
|
||||
foreach ($projectIds as $projectId) {
|
||||
$callback($projectId);
|
||||
$count++;
|
||||
@@ -628,14 +639,15 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
Console::info("Found {$count} projects " . ($executionEnd - $executionStart) . " seconds");
|
||||
Console::info("Found {$count} projects ".($executionEnd - $executionStart).' seconds');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $collection collectionID
|
||||
* @param array $queries
|
||||
* @param Database $database
|
||||
* @param callable|null $callback
|
||||
* @param string $collection collectionID
|
||||
* @param array $queries
|
||||
* @param Database $database
|
||||
* @param callable|null $callback
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
|
||||
@@ -655,7 +667,7 @@ class DeletesV1 extends Worker
|
||||
|
||||
$sum = count($results);
|
||||
|
||||
Console::info('Deleting chunk #' . $chunk . '. Found ' . $sum . ' documents');
|
||||
Console::info('Deleting chunk #'.$chunk.'. Found '.$sum.' documents');
|
||||
|
||||
foreach ($results as $document) {
|
||||
$this->deleteById($document, $database, $callback);
|
||||
@@ -665,11 +677,12 @@ class DeletesV1 extends Worker
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
Console::info("Deleted {$count} document by group in " . ($executionEnd - $executionStart) . " seconds");
|
||||
Console::info("Deleted {$count} document by group in ".($executionEnd - $executionStart).' seconds');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document certificates document
|
||||
* @param Document $document certificates document
|
||||
*
|
||||
* @throws \Utopia\Database\Exception\Authorization
|
||||
*/
|
||||
protected function deleteCertificates(Document $document): void
|
||||
@@ -679,10 +692,10 @@ class DeletesV1 extends Worker
|
||||
// If domain has certificate generated
|
||||
if (isset($document['certificateId'])) {
|
||||
$domainUsingCertificate = $consoleDB->findOne('domains', [
|
||||
Query::equal('certificateId', [$document['certificateId']])
|
||||
Query::equal('certificateId', [$document['certificateId']]),
|
||||
]);
|
||||
|
||||
if (!$domainUsingCertificate) {
|
||||
if (! $domainUsingCertificate) {
|
||||
$mainDomain = App::getEnv('_APP_DOMAIN_TARGET', '');
|
||||
if ($mainDomain === $document->getAttribute('domain')) {
|
||||
$domainUsingCertificate = $mainDomain;
|
||||
@@ -692,13 +705,14 @@ class DeletesV1 extends Worker
|
||||
// If certificate is still used by some domain, mark we can't delete.
|
||||
// Current domain should not be found, because we only have copy. Original domain is already deleted from database.
|
||||
if ($domainUsingCertificate) {
|
||||
Console::warning("Skipping certificate deletion, because a domain is still using it.");
|
||||
Console::warning('Skipping certificate deletion, because a domain is still using it.');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$domain = $document->getAttribute('domain');
|
||||
$directory = APP_STORAGE_CERTIFICATES . '/' . $domain;
|
||||
$directory = APP_STORAGE_CERTIFICATES.'/'.$domain;
|
||||
$checkTraversal = realpath($directory) === $directory;
|
||||
|
||||
if ($domain && $checkTraversal && is_dir($directory)) {
|
||||
@@ -708,7 +722,7 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
// Delete files, so Traefik is aware of change
|
||||
array_map('unlink', glob($directory . '/*.*'));
|
||||
array_map('unlink', glob($directory.'/*.*'));
|
||||
rmdir($directory);
|
||||
Console::info("Deleted certificate files for {$domain}");
|
||||
} else {
|
||||
@@ -719,7 +733,7 @@ class DeletesV1 extends Worker
|
||||
protected function deleteBucket(Document $document, string $projectId)
|
||||
{
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
$dbForProject->deleteCollection('bucket_' . $document->getInternalId());
|
||||
$dbForProject->deleteCollection('bucket_'.$document->getInternalId());
|
||||
|
||||
$device = $this->getFilesDevice($projectId);
|
||||
|
||||
|
||||
+17
-17
@@ -16,23 +16,25 @@ use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Functions V1 Worker');
|
||||
Console::success(APP_NAME . ' functions worker v1 has started');
|
||||
Console::success(APP_NAME.' functions worker v1 has started');
|
||||
|
||||
class FunctionsV1 extends Worker
|
||||
{
|
||||
private ?Executor $executor = null;
|
||||
|
||||
public array $args = [];
|
||||
|
||||
public array $allowed = [];
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "functions";
|
||||
return 'functions';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -57,13 +59,12 @@ class FunctionsV1 extends Worker
|
||||
/**
|
||||
* Handle Event execution.
|
||||
*/
|
||||
if (!empty($events)) {
|
||||
if (! empty($events)) {
|
||||
$limit = 30;
|
||||
$sum = 30;
|
||||
$offset = 0;
|
||||
$functions = [];
|
||||
/** @var Document[] $functions */
|
||||
|
||||
while ($sum >= $limit) {
|
||||
$functions = $database->find('functions', [
|
||||
Query::limit($limit),
|
||||
@@ -73,14 +74,14 @@ class FunctionsV1 extends Worker
|
||||
$sum = \count($functions);
|
||||
$offset = $offset + $limit;
|
||||
|
||||
Console::log('Fetched ' . $sum . ' functions...');
|
||||
Console::log('Fetched '.$sum.' functions...');
|
||||
|
||||
foreach ($functions as $function) {
|
||||
if (!array_intersect($events, $function->getAttribute('events', []))) {
|
||||
if (! array_intersect($events, $function->getAttribute('events', []))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Console::success('Iterating function: ' . $function->getAttribute('name'));
|
||||
Console::success('Iterating function: '.$function->getAttribute('name'));
|
||||
|
||||
$this->execute(
|
||||
project: $project,
|
||||
@@ -93,7 +94,7 @@ class FunctionsV1 extends Worker
|
||||
user: $user
|
||||
);
|
||||
|
||||
Console::success('Triggered function: ' . $events[0]);
|
||||
Console::success('Triggered function: '.$events[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +148,7 @@ class FunctionsV1 extends Worker
|
||||
$function = $database->getDocument('functions', $function->getId());
|
||||
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found (' . $function->getId() . ')');
|
||||
throw new Exception('Function not found ('.$function->getId().')');
|
||||
}
|
||||
|
||||
if ($functionOriginal->getAttribute('schedule') !== $function->getAttribute('schedule')) { // Schedule has changed from previous run, ignore this run.
|
||||
@@ -178,7 +179,6 @@ class FunctionsV1 extends Worker
|
||||
->setUser($user)
|
||||
->setProject($project)
|
||||
->schedule(new \DateTime($next));
|
||||
;
|
||||
|
||||
$this->execute(
|
||||
project: $project,
|
||||
@@ -203,7 +203,6 @@ class FunctionsV1 extends Worker
|
||||
?Document $user = null,
|
||||
string $jwt = null
|
||||
) {
|
||||
|
||||
$user ??= new Document();
|
||||
$functionId = $function->getId();
|
||||
$deploymentId = $function->getAttribute('deployment', '');
|
||||
@@ -232,8 +231,8 @@ class FunctionsV1 extends Worker
|
||||
/** Check if runtime is supported */
|
||||
$runtimes = Config::getParam('runtimes', []);
|
||||
|
||||
if (!\array_key_exists($function->getAttribute('runtime'), $runtimes)) {
|
||||
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported', 400);
|
||||
if (! \array_key_exists($function->getAttribute('runtime'), $runtimes)) {
|
||||
throw new Exception('Runtime "'.$function->getAttribute('runtime', '').'" is not supported', 400);
|
||||
}
|
||||
|
||||
$runtime = $runtimes[$function->getAttribute('runtime')];
|
||||
@@ -265,6 +264,7 @@ class FunctionsV1 extends Worker
|
||||
|
||||
$vars = array_reduce($function['vars'] ?? [], function (array $carry, Document $var) {
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value');
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
@@ -309,7 +309,7 @@ class FunctionsV1 extends Worker
|
||||
} catch (\Throwable $th) {
|
||||
$interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt()));
|
||||
$execution
|
||||
->setAttribute('duration', (float)$interval->format('%s.%f'))
|
||||
->setAttribute('duration', (float) $interval->format('%s.%f'))
|
||||
->setAttribute('status', 'failed')
|
||||
->setAttribute('statusCode', $th->getCode())
|
||||
->setAttribute('stderr', $th->getMessage());
|
||||
@@ -339,7 +339,7 @@ class FunctionsV1 extends Worker
|
||||
/** Trigger realtime event */
|
||||
$allEvents = Event::generateEvents('functions.[functionId].executions.[executionId].update', [
|
||||
'functionId' => $function->getId(),
|
||||
'executionId' => $execution->getId()
|
||||
'executionId' => $execution->getId(),
|
||||
]);
|
||||
$target = Realtime::fromPayload(
|
||||
// Pass first, most verbose event pattern
|
||||
|
||||
@@ -4,16 +4,16 @@ use Appwrite\Resque\Worker;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Mails V1 Worker');
|
||||
Console::success(APP_NAME . ' mails worker v1 has started' . "\n");
|
||||
Console::success(APP_NAME.' mails worker v1 has started'."\n");
|
||||
|
||||
class MailsV1 extends Worker
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return "mails";
|
||||
return 'mails';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -26,10 +26,10 @@ class MailsV1 extends Worker
|
||||
|
||||
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
Console::info('Skipped mail processing. No SMTP server hostname has been set.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$recipient = $this->args['recipient'];
|
||||
$subject = $this->args['subject'];
|
||||
$name = $this->args['name'];
|
||||
@@ -56,7 +56,7 @@ class MailsV1 extends Worker
|
||||
$mail->clearBCCs();
|
||||
$mail->clearCCs();
|
||||
|
||||
$mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from));
|
||||
$mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')) : $from));
|
||||
$mail->addAddress($recipient, $name);
|
||||
$mail->Subject = $subject;
|
||||
$mail->Body = $body;
|
||||
@@ -65,7 +65,7 @@ class MailsV1 extends Worker
|
||||
try {
|
||||
$mail->send();
|
||||
} catch (\Exception $error) {
|
||||
throw new Exception('Error sending mail: ' . $error->getMessage(), 500);
|
||||
throw new Exception('Error sending mail: '.$error->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,19 +13,20 @@ use Utopia\Messaging\Adapters\SMS\Twilio;
|
||||
use Utopia\Messaging\Adapters\SMS\Vonage;
|
||||
use Utopia\Messaging\Messages\SMS;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Messaging V1 Worker');
|
||||
Console::success(APP_NAME . ' messaging worker v1 has started' . "\n");
|
||||
Console::success(APP_NAME.' messaging worker v1 has started'."\n");
|
||||
|
||||
class MessagingV1 extends Worker
|
||||
{
|
||||
protected ?Adapter $sms = null;
|
||||
|
||||
protected ?string $from = null;
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "mails";
|
||||
return 'mails';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -51,11 +52,13 @@ class MessagingV1 extends Worker
|
||||
{
|
||||
if (empty(App::getEnv('_APP_SMS_PROVIDER'))) {
|
||||
Console::info('Skipped sms processing. No Phone provider has been set.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->from)) {
|
||||
Console::info('Skipped sms processing. No phone number has been set.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -68,7 +71,7 @@ class MessagingV1 extends Worker
|
||||
try {
|
||||
$this->sms->send($message);
|
||||
} catch (\Exception $error) {
|
||||
throw new Exception('Error sending message: ' . $error->getMessage(), 500);
|
||||
throw new Exception('Error sending message: '.$error->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-15
@@ -5,10 +5,10 @@ use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Webhooks V1 Worker');
|
||||
Console::success(APP_NAME . ' webhooks worker v1 has started');
|
||||
Console::success(APP_NAME.' webhooks worker v1 has started');
|
||||
|
||||
class WebhooksV1 extends Worker
|
||||
{
|
||||
@@ -16,7 +16,7 @@ class WebhooksV1 extends Worker
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "webhooks";
|
||||
return 'webhooks';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -36,7 +36,7 @@ class WebhooksV1 extends Worker
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->errors)) {
|
||||
if (! empty($this->errors)) {
|
||||
throw new Exception(\implode(" / \n\n", $this->errors));
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ class WebhooksV1 extends Worker
|
||||
{
|
||||
$url = \rawurldecode($webhook->getAttribute('url'));
|
||||
$signatureKey = $webhook->getAttribute('signatureKey');
|
||||
$signature = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true));
|
||||
$signature = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true));
|
||||
$httpUser = $webhook->getAttribute('httpUser');
|
||||
$httpPass = $webhook->getAttribute('httpPass');
|
||||
$ch = \curl_init($webhook->getAttribute('url'));
|
||||
@@ -64,28 +64,28 @@ class WebhooksV1 extends Worker
|
||||
CURLOPT_HTTPHEADER,
|
||||
[
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . \strlen($payload),
|
||||
'X-' . APP_NAME . '-Webhook-Id: ' . $webhook->getId(),
|
||||
'X-' . APP_NAME . '-Webhook-Events: ' . implode(',', $events),
|
||||
'X-' . APP_NAME . '-Webhook-Name: ' . $webhook->getAttribute('name', ''),
|
||||
'X-' . APP_NAME . '-Webhook-User-Id: ' . $user->getId(),
|
||||
'X-' . APP_NAME . '-Webhook-Project-Id: ' . $project->getId(),
|
||||
'X-' . APP_NAME . '-Webhook-Signature: ' . $signature,
|
||||
'Content-Length: '.\strlen($payload),
|
||||
'X-'.APP_NAME.'-Webhook-Id: '.$webhook->getId(),
|
||||
'X-'.APP_NAME.'-Webhook-Events: '.implode(',', $events),
|
||||
'X-'.APP_NAME.'-Webhook-Name: '.$webhook->getAttribute('name', ''),
|
||||
'X-'.APP_NAME.'-Webhook-User-Id: '.$user->getId(),
|
||||
'X-'.APP_NAME.'-Webhook-Project-Id: '.$project->getId(),
|
||||
'X-'.APP_NAME.'-Webhook-Signature: '.$signature,
|
||||
]
|
||||
);
|
||||
|
||||
if (!$webhook->getAttribute('security', true)) {
|
||||
if (! $webhook->getAttribute('security', true)) {
|
||||
\curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
\curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
}
|
||||
|
||||
if (!empty($httpUser) && !empty($httpPass)) {
|
||||
if (! empty($httpUser) && ! empty($httpPass)) {
|
||||
\curl_setopt($ch, CURLOPT_USERPWD, "$httpUser:$httpPass");
|
||||
\curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
}
|
||||
|
||||
if (false === \curl_exec($ch)) {
|
||||
$this->errors[] = \curl_error($ch) . ' in events ' . implode(', ', $events) . ' for webhook ' . $webhook->getAttribute('name');
|
||||
$this->errors[] = \curl_error($ch).' in events '.implode(', ', $events).' for webhook '.$webhook->getAttribute('name');
|
||||
}
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
+68
-48
@@ -9,9 +9,8 @@ use Appwrite\Auth\Hash\Phpass;
|
||||
use Appwrite\Auth\Hash\Scrypt;
|
||||
use Appwrite\Auth\Hash\Scryptmodified;
|
||||
use Appwrite\Auth\Hash\Sha;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
@@ -26,49 +25,69 @@ class Auth
|
||||
'phpass',
|
||||
'scrypt',
|
||||
'scryptMod',
|
||||
'plaintext'
|
||||
'plaintext',
|
||||
];
|
||||
|
||||
public const DEFAULT_ALGO = 'argon2';
|
||||
|
||||
public const DEFAULT_ALGO_OPTIONS = ['type' => 'argon2', 'memoryCost' => 2048, 'timeCost' => 4, 'threads' => 3];
|
||||
|
||||
/**
|
||||
* User Roles.
|
||||
*/
|
||||
public const USER_ROLE_ANY = 'any';
|
||||
|
||||
public const USER_ROLE_GUESTS = 'guests';
|
||||
|
||||
public const USER_ROLE_USERS = 'users';
|
||||
|
||||
public const USER_ROLE_ADMIN = 'admin';
|
||||
|
||||
public const USER_ROLE_DEVELOPER = 'developer';
|
||||
|
||||
public const USER_ROLE_OWNER = 'owner';
|
||||
|
||||
public const USER_ROLE_APPS = 'apps';
|
||||
|
||||
public const USER_ROLE_SYSTEM = 'system';
|
||||
|
||||
/**
|
||||
* Token Types.
|
||||
*/
|
||||
public const TOKEN_TYPE_LOGIN = 1; // Deprecated
|
||||
|
||||
public const TOKEN_TYPE_VERIFICATION = 2;
|
||||
|
||||
public const TOKEN_TYPE_RECOVERY = 3;
|
||||
|
||||
public const TOKEN_TYPE_INVITE = 4;
|
||||
|
||||
public const TOKEN_TYPE_MAGIC_URL = 5;
|
||||
|
||||
public const TOKEN_TYPE_PHONE = 6;
|
||||
|
||||
/**
|
||||
* Session Providers.
|
||||
*/
|
||||
public const SESSION_PROVIDER_EMAIL = 'email';
|
||||
|
||||
public const SESSION_PROVIDER_ANONYMOUS = 'anonymous';
|
||||
|
||||
public const SESSION_PROVIDER_MAGIC_URL = 'magic-url';
|
||||
|
||||
public const SESSION_PROVIDER_PHONE = 'phone';
|
||||
|
||||
/**
|
||||
* Token Expiration times.
|
||||
*/
|
||||
public const TOKEN_EXPIRATION_LOGIN_LONG = 31536000; /* 1 year */
|
||||
|
||||
public const TOKEN_EXPIRATION_LOGIN_SHORT = 3600; /* 1 hour */
|
||||
|
||||
public const TOKEN_EXPIRATION_RECOVERY = 3600; /* 1 hour */
|
||||
|
||||
public const TOKEN_EXPIRATION_CONFIRM = 3600 * 24 * 7; /* 7 days */
|
||||
|
||||
public const TOKEN_EXPIRATION_PHONE = 60 * 15; /* 15 minutes */
|
||||
|
||||
/**
|
||||
@@ -94,7 +113,6 @@ class Auth
|
||||
* Set Cookie Name.
|
||||
*
|
||||
* @param $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function setCookieName($string)
|
||||
@@ -105,9 +123,8 @@ class Auth
|
||||
/**
|
||||
* Encode Session.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $secret
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $secret
|
||||
* @return string
|
||||
*/
|
||||
public static function encodeSession($id, $secret)
|
||||
@@ -121,8 +138,7 @@ class Auth
|
||||
/**
|
||||
* Decode Session.
|
||||
*
|
||||
* @param string $session
|
||||
*
|
||||
* @param string $session
|
||||
* @return array
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -132,7 +148,7 @@ class Auth
|
||||
$session = \json_decode(\base64_decode($session), true);
|
||||
$default = ['id' => null, 'secret' => ''];
|
||||
|
||||
if (!\is_array($session)) {
|
||||
if (! \is_array($session)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
@@ -145,7 +161,6 @@ class Auth
|
||||
* One-way encryption
|
||||
*
|
||||
* @param $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function hash(string $string)
|
||||
@@ -158,10 +173,9 @@ class Auth
|
||||
*
|
||||
* One way string hashing for user passwords
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $algo hashing algorithm to use
|
||||
* @param array $options algo-specific options
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $algo hashing algorithm to use
|
||||
* @param array $options algo-specific options
|
||||
* @return bool|string|null
|
||||
*/
|
||||
public static function passwordHash(string $string, string $algo, array $options = [])
|
||||
@@ -172,45 +186,51 @@ class Auth
|
||||
$options = Auth::DEFAULT_ALGO_OPTIONS;
|
||||
}
|
||||
|
||||
if (!\in_array($algo, Auth::SUPPORTED_ALGOS)) {
|
||||
throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.');
|
||||
if (! \in_array($algo, Auth::SUPPORTED_ALGOS)) {
|
||||
throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.');
|
||||
}
|
||||
|
||||
switch ($algo) {
|
||||
case 'argon2':
|
||||
$hasher = new Argon2($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'bcrypt':
|
||||
$hasher = new Bcrypt($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'md5':
|
||||
$hasher = new Md5($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'sha':
|
||||
$hasher = new Sha($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'phpass':
|
||||
$hasher = new Phpass($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'scrypt':
|
||||
$hasher = new Scrypt($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'scryptMod':
|
||||
$hasher = new Scryptmodified($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
default:
|
||||
throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.');
|
||||
throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Password verify.
|
||||
*
|
||||
* @param string $plain
|
||||
* @param string $hash
|
||||
* @param string $algo hashing algorithm used to hash
|
||||
* @param array $options algo-specific options
|
||||
*
|
||||
* @param string $plain
|
||||
* @param string $hash
|
||||
* @param string $algo hashing algorithm used to hash
|
||||
* @param array $options algo-specific options
|
||||
* @return bool
|
||||
*/
|
||||
public static function passwordVerify(string $plain, string $hash, string $algo, array $options = [])
|
||||
@@ -221,34 +241,41 @@ class Auth
|
||||
$options = Auth::DEFAULT_ALGO_OPTIONS;
|
||||
}
|
||||
|
||||
if (!\in_array($algo, Auth::SUPPORTED_ALGOS)) {
|
||||
throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.');
|
||||
if (! \in_array($algo, Auth::SUPPORTED_ALGOS)) {
|
||||
throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.');
|
||||
}
|
||||
|
||||
switch ($algo) {
|
||||
case 'argon2':
|
||||
$hasher = new Argon2($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'bcrypt':
|
||||
$hasher = new Bcrypt($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'md5':
|
||||
$hasher = new Md5($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'sha':
|
||||
$hasher = new Sha($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'phpass':
|
||||
$hasher = new Phpass($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'scrypt':
|
||||
$hasher = new Scrypt($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'scryptMod':
|
||||
$hasher = new Scryptmodified($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
default:
|
||||
throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.');
|
||||
throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,8 +284,7 @@ class Auth
|
||||
*
|
||||
* Generate random password string
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
public static function passwordGenerator(int $length = 20): string
|
||||
@@ -271,8 +297,7 @@ class Auth
|
||||
*
|
||||
* Generate random password string
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
public static function tokenGenerator(int $length = 128): string
|
||||
@@ -285,8 +310,7 @@ class Auth
|
||||
*
|
||||
* Generate random code string
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
public static function codeGenerator(int $length = 6): string
|
||||
@@ -303,10 +327,9 @@ class Auth
|
||||
/**
|
||||
* Verify token and check that its not expired.
|
||||
*
|
||||
* @param array $tokens
|
||||
* @param int $type
|
||||
* @param string $secret
|
||||
*
|
||||
* @param array $tokens
|
||||
* @param int $type
|
||||
* @param string $secret
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function tokenVerify(array $tokens, int $type, string $secret)
|
||||
@@ -321,7 +344,7 @@ class Auth
|
||||
$token->getAttribute('secret') === self::hash($secret) &&
|
||||
DateTime::formatTz($token->getAttribute('expire')) >= DateTime::formatTz(DateTime::now())
|
||||
) {
|
||||
return (string)$token->getId();
|
||||
return (string) $token->getId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,10 +373,9 @@ class Auth
|
||||
/**
|
||||
* Verify session and check that its not expired.
|
||||
*
|
||||
* @param array $sessions
|
||||
* @param string $secret
|
||||
* @param string $expires
|
||||
*
|
||||
* @param array $sessions
|
||||
* @param string $secret
|
||||
* @param string $expires
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function sessionVerify(array $sessions, string $secret, int $expires)
|
||||
@@ -376,8 +398,7 @@ class Auth
|
||||
/**
|
||||
* Is Privileged User?
|
||||
*
|
||||
* @param array $roles
|
||||
*
|
||||
* @param array $roles
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPrivilegedUser(array $roles): bool
|
||||
@@ -396,8 +417,7 @@ class Auth
|
||||
/**
|
||||
* Is App User?
|
||||
*
|
||||
* @param array $roles
|
||||
*
|
||||
* @param array $roles
|
||||
* @return bool
|
||||
*/
|
||||
public static function isAppUser(array $roles): bool
|
||||
@@ -412,14 +432,14 @@ class Auth
|
||||
/**
|
||||
* Returns all roles for a user.
|
||||
*
|
||||
* @param Document $user
|
||||
* @param Document $user
|
||||
* @return array
|
||||
*/
|
||||
public static function getRoles(Document $user): array
|
||||
{
|
||||
$roles = [];
|
||||
|
||||
if (!self::isPrivilegedUser(Authorization::getRoles()) && !self::isAppUser(Authorization::getRoles())) {
|
||||
if (! self::isPrivilegedUser(Authorization::getRoles()) && ! self::isAppUser(Authorization::getRoles())) {
|
||||
if ($user->getId()) {
|
||||
$roles[] = Role::user($user->getId())->toString();
|
||||
$roles[] = Role::users()->toString();
|
||||
@@ -440,7 +460,7 @@ class Auth
|
||||
}
|
||||
|
||||
foreach ($user->getAttribute('memberships', []) as $node) {
|
||||
if (!isset($node['confirm']) || !$node['confirm']) {
|
||||
if (! isset($node['confirm']) || ! $node['confirm']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+12
-13
@@ -5,13 +5,13 @@ namespace Appwrite\Auth;
|
||||
abstract class Hash
|
||||
{
|
||||
/**
|
||||
* @var array $options Hashing-algo specific options
|
||||
*/
|
||||
* @var array Hashing-algo specific options
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* @param array $options Hashing-algo specific options
|
||||
*/
|
||||
* @param array $options Hashing-algo specific options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->setOptions($options);
|
||||
@@ -20,11 +20,12 @@ abstract class Hash
|
||||
/**
|
||||
* Set hashing algo options
|
||||
*
|
||||
* @param array $options Hashing-algo specific options
|
||||
*/
|
||||
* @param array $options Hashing-algo specific options
|
||||
*/
|
||||
public function setOptions(array $options): self
|
||||
{
|
||||
$this->options = \array_merge([], $this->getDefaultOptions(), $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -32,24 +33,22 @@ abstract class Hash
|
||||
* Get hashing algo options
|
||||
*
|
||||
* @return array $options Hashing-algo specific options
|
||||
*/
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
abstract public function hash(string $password): string;
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
abstract public function verify(string $password, string $hash): bool;
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@ use Appwrite\Auth\Hash;
|
||||
class Argon2 extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -25,10 +24,9 @@ class Argon2 extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
|
||||
@@ -14,8 +14,7 @@ use Appwrite\Auth\Hash;
|
||||
class Bcrypt extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -24,10 +23,9 @@ class Bcrypt extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -41,6 +39,6 @@ class Bcrypt extends Hash
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ 'cost' => 8 ];
|
||||
return ['cost' => 8];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ use Appwrite\Auth\Hash;
|
||||
class Md5 extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -22,10 +21,9 @@ class Md5 extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
|
||||
@@ -39,6 +39,7 @@ class Phpass extends Hash
|
||||
* Alphabet used in itoa64 conversions.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
protected string $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||
@@ -59,8 +60,7 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -68,7 +68,7 @@ class Phpass extends Hash
|
||||
$options = $this->getDefaultOptions();
|
||||
|
||||
$random = '';
|
||||
if (CRYPT_BLOWFISH === 1 && !$options['portable_hashes']) {
|
||||
if (CRYPT_BLOWFISH === 1 && ! $options['portable_hashes']) {
|
||||
$random = $this->getRandomBytes(16, $options);
|
||||
$hash = crypt($password, $this->gensaltBlowfish($random, $options));
|
||||
if (strlen($hash) === 60) {
|
||||
@@ -92,10 +92,9 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -114,15 +113,16 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
* @param int $count
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*
|
||||
* @throws Exception Thows an Exception if the $count parameter is not a positive integer.
|
||||
*/
|
||||
protected function getRandomBytes(int $count, array $options): string
|
||||
{
|
||||
if (!is_int($count) || $count < 1) {
|
||||
if (! is_int($count) || $count < 1) {
|
||||
throw new \Exception('Argument count must be a positive integer');
|
||||
}
|
||||
$output = '';
|
||||
@@ -135,7 +135,7 @@ class Phpass extends Hash
|
||||
$output = '';
|
||||
|
||||
for ($i = 0; $i < $count; $i += 16) {
|
||||
$options['iteration_count_log2'] = md5(microtime() . $options['iteration_count_log2']);
|
||||
$options['iteration_count_log2'] = md5(microtime().$options['iteration_count_log2']);
|
||||
$output .= md5($options['iteration_count_log2'], true);
|
||||
}
|
||||
|
||||
@@ -146,47 +146,48 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $input
|
||||
* @param int $count
|
||||
* @param string $input
|
||||
* @param int $count
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*
|
||||
* @throws Exception Thows an Exception if the $count parameter is not a positive integer.
|
||||
*/
|
||||
protected function encode64($input, $count)
|
||||
{
|
||||
if (!is_int($count) || $count < 1) {
|
||||
if (! is_int($count) || $count < 1) {
|
||||
throw new \Exception('Argument count must be a positive integer');
|
||||
}
|
||||
$output = '';
|
||||
$i = 0;
|
||||
do {
|
||||
$value = ord($input[$i++]);
|
||||
$output .= $this->itoa64[$value & 0x3f];
|
||||
$output .= $this->itoa64[$value & 0x3F];
|
||||
if ($i < $count) {
|
||||
$value |= ord($input[$i]) << 8;
|
||||
}
|
||||
$output .= $this->itoa64[($value >> 6) & 0x3f];
|
||||
$output .= $this->itoa64[($value >> 6) & 0x3F];
|
||||
if ($i++ >= $count) {
|
||||
break;
|
||||
}
|
||||
if ($i < $count) {
|
||||
$value |= ord($input[$i]) << 16;
|
||||
}
|
||||
$output .= $this->itoa64[($value >> 12) & 0x3f];
|
||||
$output .= $this->itoa64[($value >> 12) & 0x3F];
|
||||
if ($i++ >= $count) {
|
||||
break;
|
||||
}
|
||||
$output .= $this->itoa64[($value >> 18) & 0x3f];
|
||||
$output .= $this->itoa64[($value >> 18) & 0x3F];
|
||||
} while ($i < $count);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $input
|
||||
* @param string $input
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function gensaltPrivate($input, $options)
|
||||
@@ -199,10 +200,10 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $password
|
||||
* @param String $setting
|
||||
* @param string $password
|
||||
* @param string $setting
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function cryptPrivate($password, $setting)
|
||||
@@ -233,9 +234,9 @@ class Phpass extends Hash
|
||||
* consequently in lower iteration counts and hashes that are
|
||||
* quicker to crack (by non-PHP code).
|
||||
*/
|
||||
$hash = md5($salt . $password, true);
|
||||
$hash = md5($salt.$password, true);
|
||||
do {
|
||||
$hash = md5($hash . $password, true);
|
||||
$hash = md5($hash.$password, true);
|
||||
} while (--$count);
|
||||
$output = substr($setting, 0, 12);
|
||||
$output .= $this->encode64($hash, 16);
|
||||
@@ -244,9 +245,9 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $input
|
||||
* @param string $input
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function gensaltBlowfish($input, $options)
|
||||
@@ -278,11 +279,11 @@ class Phpass extends Hash
|
||||
$c2 = ord($input[$i++]);
|
||||
$c1 |= $c2 >> 4;
|
||||
$output .= $itoa64[$c1];
|
||||
$c1 = ($c2 & 0x0f) << 2;
|
||||
$c1 = ($c2 & 0x0F) << 2;
|
||||
$c2 = ord($input[$i++]);
|
||||
$c1 |= $c2 >> 6;
|
||||
$output .= $itoa64[$c1];
|
||||
$output .= $itoa64[$c2 & 0x3f];
|
||||
$output .= $itoa64[$c2 & 0x3F];
|
||||
} while (1);
|
||||
|
||||
return $output;
|
||||
|
||||
@@ -17,8 +17,7 @@ use Appwrite\Auth\Hash;
|
||||
class Scrypt extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -29,10 +28,9 @@ class Scrypt extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -46,6 +44,6 @@ class Scrypt extends Hash
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ 'costCpu' => 8, 'costMemory' => 14, 'costParallel' => 1, 'length' => 64 ];
|
||||
return ['costCpu' => 8, 'costMemory' => 14, 'costParallel' => 1, 'length' => 64];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ use Appwrite\Auth\Hash;
|
||||
class Scryptmodified extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -33,10 +32,9 @@ class Scryptmodified extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -50,7 +48,7 @@ class Scryptmodified extends Hash
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ ];
|
||||
return [];
|
||||
}
|
||||
|
||||
private function generateDerivedKey(string $password)
|
||||
@@ -60,7 +58,7 @@ class Scryptmodified extends Hash
|
||||
$saltBytes = \base64_decode($options['salt']);
|
||||
$saltSeparatorBytes = \base64_decode($options['saltSeparator']);
|
||||
|
||||
$derivedKey = \scrypt(\utf8_encode($password), $saltBytes . $saltSeparatorBytes, 16384, 8, 1, 64);
|
||||
$derivedKey = \scrypt(\utf8_encode($password), $saltBytes.$saltSeparatorBytes, 16384, 8, 1, 64);
|
||||
$derivedKey = \hex2bin($derivedKey);
|
||||
|
||||
return $derivedKey;
|
||||
|
||||
@@ -16,8 +16,7 @@ use Appwrite\Auth\Hash;
|
||||
class Sha extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -28,10 +27,9 @@ class Sha extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -45,6 +43,6 @@ class Sha extends Hash
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ 'version' => 'sha3-512' ];
|
||||
return ['version' => 'sha3-512'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ abstract class OAuth2
|
||||
/**
|
||||
* OAuth2 constructor.
|
||||
*
|
||||
* @param string $appId
|
||||
* @param string $appSecret
|
||||
* @param string $callback
|
||||
* @param array $state
|
||||
* @param array $scopes
|
||||
* @param string $appId
|
||||
* @param string $appSecret
|
||||
* @param string $callback
|
||||
* @param array $state
|
||||
* @param array $scopes
|
||||
*/
|
||||
public function __construct(string $appId, string $appSecret, string $callback, array $state = [], array $scopes = [])
|
||||
{
|
||||
@@ -60,22 +60,19 @@ abstract class OAuth2
|
||||
abstract public function getLoginURL(): string;
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getTokens(string $code): array;
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
abstract public function refreshTokens(string $refreshToken): array;
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getUserEmail(string $accessToken): string;
|
||||
@@ -83,28 +80,25 @@ abstract class OAuth2
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function isEmailVerified(string $accessToken): bool;
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getUserName(string $accessToken): string;
|
||||
|
||||
/**
|
||||
* @param $scope
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function addScope(string $scope): OAuth2
|
||||
{
|
||||
// Add a scope to the scopes array if it isn't already present
|
||||
if (!\in_array($scope, $this->scopes)) {
|
||||
if (! \in_array($scope, $this->scopes)) {
|
||||
$this->scopes[] = $scope;
|
||||
}
|
||||
|
||||
@@ -120,8 +114,7 @@ abstract class OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken(string $code): string
|
||||
@@ -132,8 +125,7 @@ abstract class OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return string
|
||||
*/
|
||||
public function getRefreshToken(string $code): string
|
||||
@@ -144,8 +136,7 @@ abstract class OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessTokenExpiry(string $code): string
|
||||
@@ -160,7 +151,6 @@ abstract class OAuth2
|
||||
// json_decoding
|
||||
/**
|
||||
* @param $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parseState(string $state)
|
||||
@@ -169,11 +159,10 @@ abstract class OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param array $headers
|
||||
* @param string $payload
|
||||
*
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param array $headers
|
||||
* @param string $payload
|
||||
* @return string
|
||||
*/
|
||||
protected function request(string $method, string $url = '', array $headers = [], string $payload = ''): string
|
||||
@@ -185,11 +174,11 @@ abstract class OAuth2
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
\curl_setopt($ch, CURLOPT_USERAGENT, 'Appwrite OAuth2');
|
||||
|
||||
if (!empty($payload)) {
|
||||
if (! empty($payload)) {
|
||||
\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
|
||||
@@ -197,6 +186,6 @@ abstract class OAuth2
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
return (string)$response;
|
||||
return (string) $response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class Amazon extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"profile"
|
||||
'profile',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -37,8 +37,7 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*
|
||||
* @param string $state
|
||||
* @return array
|
||||
*/
|
||||
public function parseState(string $state)
|
||||
@@ -46,24 +45,22 @@ class Amazon extends OAuth2
|
||||
return \json_decode(\html_entity_decode($state), true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.amazon.com/ap/oa?' . \http_build_query([
|
||||
return 'https://www.amazon.com/ap/oa?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback
|
||||
'redirect_uri' => $this->callback,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -79,7 +76,7 @@ class Amazon extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -88,8 +85,7 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -103,7 +99,7 @@ class Amazon extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken
|
||||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -115,8 +111,7 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -127,8 +122,7 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -143,20 +137,18 @@ class Amazon extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Amazon sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -167,16 +159,16 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ class Apple extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"name",
|
||||
"email"
|
||||
'name',
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -46,19 +46,18 @@ class Apple extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://appleid.apple.com/auth/authorize?' . \http_build_query([
|
||||
return 'https://appleid.apple.com/auth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code',
|
||||
'response_mode' => 'form_post',
|
||||
'scope' => \implode(' ', $this->getScopes())
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -86,8 +85,7 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -116,8 +114,7 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -126,8 +123,7 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -140,8 +136,7 @@ class Apple extends OAuth2
|
||||
*
|
||||
* @link https://developer.apple.com/forums/thread/121411
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -154,15 +149,14 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
if (
|
||||
isset($this->claims['email']) &&
|
||||
!empty($this->claims['email']) &&
|
||||
! empty($this->claims['email']) &&
|
||||
isset($this->claims['email_verified']) &&
|
||||
$this->claims['email_verified'] === 'true'
|
||||
) {
|
||||
@@ -183,7 +177,7 @@ class Apple extends OAuth2
|
||||
$keyfile = (isset($secret['p8'])) ? $secret['p8'] : ''; // Your p8 Key file
|
||||
$keyID = (isset($secret['keyID'])) ? $secret['keyID'] : ''; // Your Key ID
|
||||
$teamID = (isset($secret['teamID'])) ? $secret['teamID'] : ''; // Your Team ID (see Developer Portal)
|
||||
$bundleID = $this->appID; // Your Bundle ID
|
||||
$bundleID = $this->appID; // Your Bundle ID
|
||||
|
||||
$headers = [
|
||||
'alg' => 'ES256',
|
||||
@@ -200,22 +194,21 @@ class Apple extends OAuth2
|
||||
|
||||
$pkey = \openssl_pkey_get_private($keyfile);
|
||||
|
||||
$payload = $this->encode(\json_encode($headers)) . '.' . $this->encode(\json_encode($claims));
|
||||
$payload = $this->encode(\json_encode($headers)).'.'.$this->encode(\json_encode($claims));
|
||||
|
||||
$signature = '';
|
||||
|
||||
$success = \openssl_sign($payload, $signature, $pkey, OPENSSL_ALGO_SHA256);
|
||||
|
||||
if (!$success) {
|
||||
if (! $success) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $payload . '.' . $this->encode($this->fromDER($signature, 64));
|
||||
return $payload.'.'.$this->encode($this->fromDER($signature, 64));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
*
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
protected function encode($data): string
|
||||
@@ -224,7 +217,7 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param string $data
|
||||
*/
|
||||
protected function retrievePositiveInteger(string $data): string
|
||||
{
|
||||
@@ -236,8 +229,8 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $der
|
||||
* @param int $partLength
|
||||
* @param string $der
|
||||
* @param int $partLength
|
||||
*/
|
||||
protected function fromDER(string $der, int $partLength): string
|
||||
{
|
||||
@@ -270,6 +263,6 @@ class Apple extends OAuth2
|
||||
$S = $this->retrievePositiveInteger(\mb_substr($hex, 4, $Sl * 2, '8bit'));
|
||||
$S = \str_pad($S, $partLength, '0', STR_PAD_LEFT);
|
||||
|
||||
return \pack('H*', $R . $S);
|
||||
return \pack('H*', $R.$S);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class Auth0 extends OAuth2
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
'offline_access',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -42,18 +42,17 @@ class Auth0 extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://' . $this->getAuth0Domain() . '/authorize?' . \http_build_query([
|
||||
return 'https://'.$this->getAuth0Domain().'/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -62,7 +61,7 @@ class Auth0 extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getAuth0Domain() . '/oauth/token',
|
||||
'https://'.$this->getAuth0Domain().'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
@@ -70,7 +69,7 @@ class Auth0 extends OAuth2
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -78,10 +77,8 @@ class Auth0 extends OAuth2
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -89,13 +86,13 @@ class Auth0 extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getAuth0Domain() . '/oauth/token',
|
||||
'https://'.$this->getAuth0Domain().'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -107,8 +104,7 @@ class Auth0 extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -119,8 +115,7 @@ class Auth0 extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -135,8 +130,7 @@ class Auth0 extends OAuth2
|
||||
*
|
||||
* @link https://auth0.com/docs/api/authentication?javascript#user-profile
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -151,8 +145,7 @@ class Auth0 extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -163,15 +156,14 @@ class Auth0 extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://' . $this->getAuth0Domain() . '/userinfo', $headers);
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://'.$this->getAuth0Domain().'/userinfo', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -214,6 +206,7 @@ class Auth0 extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class Authentik extends OAuth2
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
'offline_access',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -42,18 +42,17 @@ class Authentik extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://' . $this->getAuthentikDomain() . '/application/o/authorize?' . \http_build_query([
|
||||
return 'https://'.$this->getAuthentikDomain().'/application/o/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -62,7 +61,7 @@ class Authentik extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getAuthentikDomain() . '/application/o/token/',
|
||||
'https://'.$this->getAuthentikDomain().'/application/o/token/',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
@@ -70,17 +69,16 @@ class Authentik extends OAuth2
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -88,13 +86,13 @@ class Authentik extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getAuthentikDomain() . '/application/o/token/',
|
||||
'https://'.$this->getAuthentikDomain().'/application/o/token/',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -106,8 +104,7 @@ class Authentik extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -122,8 +119,7 @@ class Authentik extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -140,8 +136,7 @@ class Authentik extends OAuth2
|
||||
/**
|
||||
* Check if the User email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -156,8 +151,7 @@ class Authentik extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -171,16 +165,15 @@ class Authentik extends OAuth2
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
/**
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://' . $this->getAuthentikDomain() . '/application/o/userinfo/', $headers);
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://'.$this->getAuthentikDomain().'/application/o/userinfo/', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -199,7 +192,7 @@ class Authentik extends OAuth2
|
||||
return $secret['clientSecret'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Extracts the authentik Domain from the JSON stored in appSecret
|
||||
*
|
||||
* @return string
|
||||
@@ -207,6 +200,7 @@ class Authentik extends OAuth2
|
||||
protected function getAuthentikDomain(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
|
||||
return $secret['authentikDomain'] ?? '';
|
||||
}
|
||||
|
||||
@@ -222,6 +216,7 @@ class Authentik extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,18 +36,17 @@ class Autodesk extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://developer.api.autodesk.com/authentication/v1/authorize?' . \http_build_query([
|
||||
return 'https://developer.api.autodesk.com/authentication/v1/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -63,7 +62,7 @@ class Autodesk extends OAuth2
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
);
|
||||
|
||||
@@ -74,8 +73,7 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -105,8 +103,7 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -117,8 +114,7 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -133,8 +129,7 @@ class Autodesk extends OAuth2
|
||||
*
|
||||
* @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -149,8 +144,7 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -161,14 +155,13 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://developer.api.autodesk.com/userprofile/v1/users/@me', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class Bitbucket extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://bitbucket.org/site/oauth2/authorize?' . \http_build_query([
|
||||
return 'https://bitbucket.org/site/oauth2/authorize?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
@@ -46,8 +46,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -63,7 +62,7 @@ class Bitbucket extends OAuth2
|
||||
'code' => $code,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -72,8 +71,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -87,7 +85,7 @@ class Bitbucket extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken
|
||||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -99,8 +97,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -111,8 +108,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -125,8 +121,7 @@ class Bitbucket extends OAuth2
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -141,8 +136,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -153,17 +147,16 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
|
||||
$emails = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token=' . \urlencode($accessToken));
|
||||
$emails = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token='.\urlencode($accessToken));
|
||||
$emails = \json_decode($emails, true);
|
||||
if (isset($emails['values'])) {
|
||||
foreach ($emails['values'] as $email) {
|
||||
@@ -175,6 +168,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,17 +47,16 @@ class Bitly extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'authorize?' .
|
||||
return $this->endpoint.'authorize?'.
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -65,14 +64,14 @@ class Bitly extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$response = $this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint . 'oauth/access_token',
|
||||
["Content-Type: application/x-www-form-urlencoded"],
|
||||
$this->resourceEndpoint.'oauth/access_token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"code" => $code,
|
||||
"redirect_uri" => $this->callback,
|
||||
"state" => \json_encode($this->state)
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
])
|
||||
);
|
||||
|
||||
@@ -85,21 +84,20 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$response = $this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint . 'oauth/access_token',
|
||||
["Content-Type: application/x-www-form-urlencoded"],
|
||||
$this->resourceEndpoint.'oauth/access_token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"refresh_token" => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
);
|
||||
|
||||
@@ -115,8 +113,7 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -127,8 +124,7 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -151,8 +147,7 @@ class Bitly extends OAuth2
|
||||
*
|
||||
* @link https://dev.bitly.com/api-reference#getUser
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -161,8 +156,7 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -173,19 +167,18 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
"Accept: application/json"
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Accept: application/json',
|
||||
];
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', $this->resourceEndpoint . "v4/user", $headers), true);
|
||||
$this->user = \json_decode($this->request('GET', $this->resourceEndpoint.'v4/user', $headers), true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
||||
@@ -49,7 +49,7 @@ class Box extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . 'authorize?' .
|
||||
$url = $this->endpoint.'authorize?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
@@ -62,8 +62,7 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -72,15 +71,15 @@ class Box extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'token',
|
||||
$this->endpoint.'token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"code" => $code,
|
||||
"grant_type" => "authorization_code",
|
||||
"scope" => \implode(',', $this->getScopes()),
|
||||
"redirect_uri" => $this->callback
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
'scope' => \implode(',', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -89,8 +88,7 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -98,13 +96,13 @@ class Box extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'token',
|
||||
$this->endpoint.'token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"refresh_token" => $refreshToken,
|
||||
"grant_type" => "refresh_token",
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -116,8 +114,7 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -128,8 +125,7 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -144,20 +140,18 @@ class Box extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Box sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -168,19 +162,18 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
$header = [
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
];
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint . 'me',
|
||||
$this->resourceEndpoint.'me',
|
||||
$header
|
||||
);
|
||||
$this->user = \json_decode($user, true);
|
||||
|
||||
@@ -24,7 +24,7 @@ class Dailymotion extends OAuth2
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'userinfo',
|
||||
'email'
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -34,7 +34,7 @@ class Dailymotion extends OAuth2
|
||||
'email',
|
||||
'id',
|
||||
'fullname',
|
||||
'verified'
|
||||
'verified',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -68,21 +68,20 @@ class Dailymotion extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->authEndpoint . '?' .
|
||||
$url = $this->authEndpoint.'?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes())
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
]);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -90,33 +89,31 @@ class Dailymotion extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
["Content-Type: application/x-www-form-urlencoded"],
|
||||
$this->endpoint.'/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"redirect_uri" => $this->callback,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback,
|
||||
'code' => $code,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -130,13 +127,11 @@ class Dailymotion extends OAuth2
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -149,8 +144,7 @@ class Dailymotion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -166,8 +160,7 @@ class Dailymotion extends OAuth2
|
||||
*
|
||||
* @link https://developers.dailymotion.com/api/#user-fields
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -178,23 +171,20 @@ class Dailymotion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
|
||||
$username = $user['fullname'] ?? '';
|
||||
|
||||
return $username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -202,8 +192,8 @@ class Dailymotion extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->endpoint . '/user/me?fields=' . \implode(',', $this->getFields()),
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)],
|
||||
$this->endpoint.'/user/me?fields='.\implode(',', $this->getFields()),
|
||||
['Authorization: Bearer '.\urlencode($accessToken)],
|
||||
);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ class Discord extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'identify',
|
||||
'email'
|
||||
'identify',
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -45,21 +45,20 @@ 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,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback
|
||||
'redirect_uri' => $this->callback,
|
||||
]);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -67,7 +66,7 @@ class Discord extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth2/token',
|
||||
$this->endpoint.'/oauth2/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
@@ -75,7 +74,7 @@ class Discord extends OAuth2
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'scope' => \implode(' ', $this->getScopes())
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -84,15 +83,14 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth2/token',
|
||||
$this->endpoint.'/oauth2/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -110,8 +108,7 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -122,8 +119,7 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -138,8 +134,7 @@ class Discord extends OAuth2
|
||||
*
|
||||
* @link https://discord.com/developers/docs/resources/user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -154,8 +149,7 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -166,8 +160,7 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -175,8 +168,8 @@ class Discord extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->endpoint . '/users/@me',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
$this->endpoint.'/users/@me',
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -45,21 +45,20 @@ class Disqus extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . 'oauth/2.0/authorize/?' .
|
||||
$url = $this->endpoint.'oauth/2.0/authorize/?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(',', $this->getScopes())
|
||||
'scope' => \implode(',', $this->getScopes()),
|
||||
]);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -67,7 +66,7 @@ class Disqus extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'oauth/2.0/access_token/',
|
||||
$this->endpoint.'oauth/2.0/access_token/',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
@@ -79,19 +78,19 @@ class Disqus extends OAuth2
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'oauth/2.0/access_token/?',
|
||||
$this->endpoint.'oauth/2.0/access_token/?',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -104,12 +103,12 @@ class Disqus extends OAuth2
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
*
|
||||
* @param string $token
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -122,8 +121,7 @@ class Disqus extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -136,13 +134,11 @@ class Disqus extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
|
||||
// Look out for the change in their enpoint.
|
||||
// It's in Beta so they may provide a parameter in the future.
|
||||
// https://disqus.com/api/docs/users/details/
|
||||
@@ -151,8 +147,7 @@ class Disqus extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -165,8 +160,7 @@ class Disqus extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -174,10 +168,10 @@ class Disqus extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->endpoint . '3.0/users/details.json?' . \http_build_query([
|
||||
$this->endpoint.'3.0/users/details.json?'.\http_build_query([
|
||||
'access_token' => $accessToken,
|
||||
'api_key' => $this->appID,
|
||||
'api_secret' => $this->appSecret
|
||||
'api_secret' => $this->appSecret,
|
||||
]),
|
||||
);
|
||||
$this->user = \json_decode($user, true)['response'];
|
||||
|
||||
@@ -38,17 +38,16 @@ class Dropbox extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.dropbox.com/oauth2/authorize?' . \http_build_query([
|
||||
return 'https://www.dropbox.com/oauth2/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -64,7 +63,7 @@ class Dropbox extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -73,8 +72,7 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -88,7 +86,7 @@ class Dropbox extends OAuth2
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -100,8 +98,7 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -112,8 +109,7 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -128,8 +124,7 @@ class Dropbox extends OAuth2
|
||||
*
|
||||
* @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -144,8 +139,7 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -156,14 +150,13 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('POST', 'https://api.dropboxapi.com/2/users/get_current_account', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ class Etsy extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"email_r",
|
||||
"profile_r",
|
||||
'email_r',
|
||||
'profile_r',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ class Etsy extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.etsy.com/oauth/connect/oauth/authorize?' . \http_build_query([
|
||||
return 'https://www.etsy.com/oauth/connect/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code',
|
||||
@@ -76,8 +76,7 @@ class Etsy extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -87,7 +86,7 @@ class Etsy extends OAuth2
|
||||
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
@@ -103,8 +102,7 @@ class Etsy extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -113,7 +111,7 @@ class Etsy extends OAuth2
|
||||
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -131,7 +129,6 @@ class Etsy extends OAuth2
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -143,7 +140,6 @@ class Etsy extends OAuth2
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -156,20 +152,18 @@ class Etsy extends OAuth2
|
||||
*
|
||||
* OAuth is only allowed if account has been verified through Etsy, itself.
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -178,21 +172,20 @@ class Etsy extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (!empty($this->user)) {
|
||||
if (! empty($this->user)) {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
$headers = ['Authorization: Bearer ' . $accessToken];
|
||||
$headers = ['Authorization: Bearer '.$accessToken];
|
||||
|
||||
$this->user = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://api.etsy.com/v3/application/users/' . $this->getUserID($accessToken),
|
||||
'https://api.etsy.com/v3/application/users/'.$this->getUserID($accessToken),
|
||||
), true);
|
||||
|
||||
return $this->user;
|
||||
|
||||
@@ -25,7 +25,7 @@ class Facebook extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'email'
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -41,17 +41,16 @@ class Facebook extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.facebook.com/' . $this->version . '/dialog/oauth?' . \http_build_query([
|
||||
return 'https://www.facebook.com/'.$this->version.'/dialog/oauth?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -59,11 +58,11 @@ class Facebook extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' . \http_build_query([
|
||||
'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -72,20 +71,19 @@ class Facebook extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' . \http_build_query([
|
||||
'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -97,8 +95,7 @@ class Facebook extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -109,8 +106,7 @@ class Facebook extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -125,20 +121,18 @@ class Facebook extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Facebook sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -149,14 +143,13 @@ class Facebook extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://graph.facebook.com/' . $this->version . '/me?fields=email,name&access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://graph.facebook.com/'.$this->version.'/me?fields=email,name&access_token='.\urlencode($accessToken));
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -36,17 +36,16 @@ class Github extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://github.com/login/oauth/authorize?' . \http_build_query([
|
||||
return 'https://github.com/login/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -60,7 +59,7 @@ class Github extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
);
|
||||
|
||||
@@ -73,8 +72,7 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -87,7 +85,7 @@ class Github extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken
|
||||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
);
|
||||
|
||||
@@ -103,8 +101,7 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -115,8 +112,7 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -131,8 +127,7 @@ class Github extends OAuth2
|
||||
*
|
||||
* @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -147,8 +142,7 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -159,16 +153,15 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token ' . \urlencode($accessToken)]), true);
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token '.\urlencode($accessToken)]), true);
|
||||
|
||||
$emails = $this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token ' . \urlencode($accessToken)]);
|
||||
$emails = $this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token '.\urlencode($accessToken)]);
|
||||
|
||||
$emails = \json_decode($emails, true);
|
||||
foreach ($emails as $email) {
|
||||
|
||||
@@ -23,7 +23,7 @@ class Gitlab extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'read_user'
|
||||
'read_user',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -39,18 +39,17 @@ class Gitlab extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->getEndpoint() . '/oauth/authorize?' . \http_build_query([
|
||||
return $this->getEndpoint().'/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -58,12 +57,12 @@ class Gitlab extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->getEndpoint() . '/oauth/token?' . \http_build_query([
|
||||
$this->getEndpoint().'/oauth/token?'.\http_build_query([
|
||||
'code' => $code,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getAppSecret()['clientSecret'],
|
||||
'redirect_uri' => $this->callback,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -72,19 +71,18 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->getEndpoint() . '/oauth/token?' . \http_build_query([
|
||||
$this->getEndpoint().'/oauth/token?'.\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getAppSecret()['clientSecret'],
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -96,8 +94,7 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -112,8 +109,7 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -128,8 +124,7 @@ class Gitlab extends OAuth2
|
||||
*
|
||||
* @link https://docs.gitlab.com/ee/api/users.html#list-current-user-for-normal-users
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -144,8 +139,7 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -156,14 +150,13 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', $this->getEndpoint() . '/api/v4/user?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', $this->getEndpoint().'/api/v4/user?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -182,10 +175,10 @@ class Gitlab extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts the Tenant Id from the JSON stored in appSecret. Defaults to 'common' as a fallback
|
||||
*
|
||||
@@ -196,6 +189,7 @@ class Gitlab extends OAuth2
|
||||
$defaultEndpoint = 'https://gitlab.com';
|
||||
$secret = $this->getAppSecret();
|
||||
$endpoint = $secret['endpoint'] ?? $defaultEndpoint;
|
||||
|
||||
return empty($endpoint) ? $defaultEndpoint : $endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class Google extends OAuth2
|
||||
protected array $scopes = [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
'openid'
|
||||
'openid',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -48,18 +48,17 @@ class Google extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://accounts.google.com/o/oauth2/v2/auth?' . \http_build_query([
|
||||
return 'https://accounts.google.com/o/oauth2/v2/auth?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -67,13 +66,13 @@ class Google extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://oauth2.googleapis.com/token?' . \http_build_query([
|
||||
'https://oauth2.googleapis.com/token?'.\http_build_query([
|
||||
'code' => $code,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => null,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -82,19 +81,18 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://oauth2.googleapis.com/token?' . \http_build_query([
|
||||
'https://oauth2.googleapis.com/token?'.\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -106,8 +104,7 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -118,8 +115,7 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -134,8 +130,7 @@ class Google extends OAuth2
|
||||
*
|
||||
* @link https://www.oauth.com/oauth2-servers/signing-in-with-google/verifying-the-user-info/
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -150,8 +145,7 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -162,14 +156,13 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://www.googleapis.com/oauth2/v3/userinfo?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class Linkedin extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.linkedin.com/oauth/v2/authorization?' . \http_build_query([
|
||||
return 'https://www.linkedin.com/oauth/v2/authorization?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
@@ -60,8 +60,7 @@ class Linkedin extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -80,12 +79,12 @@ class Linkedin extends OAuth2
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -106,12 +105,12 @@ class Linkedin extends OAuth2
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -122,13 +121,12 @@ class Linkedin extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer ' . \urlencode($accessToken)]), true);
|
||||
$email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer '.\urlencode($accessToken)]), true);
|
||||
|
||||
return $email['elements'][0]['handle~']['emailAddress'] ?? '';
|
||||
}
|
||||
@@ -138,20 +136,18 @@ class Linkedin extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Linkedin sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -164,21 +160,20 @@ class Linkedin extends OAuth2
|
||||
}
|
||||
|
||||
if (isset($user['localizedLastName'])) {
|
||||
$name = (empty($name)) ? $user['localizedLastName'] : $name . ' ' . $user['localizedLastName'];
|
||||
$name = (empty($name)) ? $user['localizedLastName'] : $name.' '.$user['localizedLastName'];
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer ' . \urlencode($accessToken)]), true);
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer '.\urlencode($accessToken)]), true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
||||
@@ -25,7 +25,7 @@ class Microsoft extends OAuth2
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'offline_access',
|
||||
'user.read'
|
||||
'user.read',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -41,19 +41,18 @@ class Microsoft extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/authorize?' . \http_build_query([
|
||||
return 'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code',
|
||||
'response_mode' => 'query'
|
||||
'response_mode' => 'query',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -62,7 +61,7 @@ class Microsoft extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/token',
|
||||
'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
@@ -70,7 +69,7 @@ class Microsoft extends OAuth2
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -79,8 +78,7 @@ class Microsoft extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -88,13 +86,13 @@ class Microsoft extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/token',
|
||||
'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -106,8 +104,7 @@ class Microsoft extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -118,8 +115,7 @@ class Microsoft extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -134,20 +130,18 @@ class Microsoft extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Microsoft sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -158,14 +152,13 @@ class Microsoft extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://graph.microsoft.com/v1.0/me', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
@@ -185,6 +178,7 @@ class Microsoft extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Exception;
|
||||
|
||||
class Mock extends OAuth2
|
||||
{
|
||||
@@ -16,7 +15,7 @@ class Mock extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'email'
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -42,17 +41,16 @@ class Mock extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'http://localhost/' . $this->version . '/mock/tests/general/oauth2?' . \http_build_query([
|
||||
return 'http://localhost/'.$this->version.'/mock/tests/general/oauth2?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -60,12 +58,12 @@ class Mock extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' .
|
||||
'http://localhost/'.$this->version.'/mock/tests/general/oauth2/token?'.
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -74,20 +72,19 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' .
|
||||
'http://localhost/'.$this->version.'/mock/tests/general/oauth2/token?'.
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -99,8 +96,7 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -111,8 +107,7 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -125,8 +120,7 @@ class Mock extends OAuth2
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -135,8 +129,7 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -147,14 +140,13 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/user?token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'http://localhost/'.$this->version.'/mock/tests/general/oauth2/user?token='.\urlencode($accessToken));
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -44,32 +44,31 @@ class Notion extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . '/oauth/authorize?' . \http_build_query([
|
||||
return $this->endpoint.'/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code',
|
||||
'state' => \json_encode($this->state),
|
||||
'owner' => 'user'
|
||||
'owner' => 'user',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
'redirect_uri' => $this->callback,
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -78,16 +77,15 @@ class Notion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -103,8 +101,7 @@ class Notion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -115,8 +112,7 @@ class Notion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -131,20 +127,18 @@ class Notion extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Notion sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -155,19 +149,18 @@ class Notion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
$headers = [
|
||||
'Notion-Version: ' . $this->version,
|
||||
'Authorization: Bearer ' . \urlencode($accessToken)
|
||||
'Notion-Version: '.$this->version,
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
];
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', $this->endpoint . '/users/me', $headers), true);
|
||||
$this->user = \json_decode($this->request('GET', $this->endpoint.'/users/me', $headers), true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
||||
@@ -16,7 +16,7 @@ class Okta extends OAuth2
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
'offline_access',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -42,18 +42,17 @@ class Okta extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/authorize?' . \http_build_query([
|
||||
return 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -62,7 +61,7 @@ class Okta extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token',
|
||||
'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
@@ -70,7 +69,7 @@ class Okta extends OAuth2
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -78,10 +77,8 @@ class Okta extends OAuth2
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -89,13 +86,13 @@ class Okta extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token',
|
||||
'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -107,8 +104,7 @@ class Okta extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -119,8 +115,7 @@ class Okta extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -135,8 +130,7 @@ class Okta extends OAuth2
|
||||
*
|
||||
* @link https://developer.okta.com/docs/reference/api/oidc/#userinfo
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -151,8 +145,7 @@ class Okta extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -163,15 +156,14 @@ class Okta extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/userinfo', $headers);
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/userinfo', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -226,6 +218,7 @@ class Okta extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class Paypal extends OAuth2
|
||||
protected array $scopes = [
|
||||
'openid',
|
||||
'profile',
|
||||
'email'
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -62,14 +62,14 @@ class Paypal extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint[$this->environment] . 'connect/?' .
|
||||
$url = $this->endpoint[$this->environment].'connect/?'.
|
||||
\http_build_query([
|
||||
'flowEntry' => 'static',
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
// paypal is not accepting localhost string into return uri
|
||||
'redirect_uri' => \str_replace("localhost", "127.0.0.1", $this->callback),
|
||||
'redirect_uri' => \str_replace('localhost', '127.0.0.1', $this->callback),
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
|
||||
@@ -77,8 +77,7 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -86,8 +85,8 @@ class Paypal extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint[$this->environment] . 'oauth2/token',
|
||||
['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)],
|
||||
$this->resourceEndpoint[$this->environment].'oauth2/token',
|
||||
['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)],
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
@@ -99,16 +98,15 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint[$this->environment] . 'oauth2/token',
|
||||
['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)],
|
||||
$this->resourceEndpoint[$this->environment].'oauth2/token',
|
||||
['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)],
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -123,8 +121,7 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -135,8 +132,7 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -148,7 +144,7 @@ class Paypal extends OAuth2
|
||||
return $email['primary'] === true;
|
||||
});
|
||||
|
||||
if (!empty($email)) {
|
||||
if (! empty($email)) {
|
||||
return $email[0]['value'];
|
||||
}
|
||||
}
|
||||
@@ -161,8 +157,7 @@ class Paypal extends OAuth2
|
||||
*
|
||||
* @link https://developer.paypal.com/docs/api/identity/v1/#userinfo_get
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -177,8 +172,7 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -189,20 +183,19 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
$header = [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
];
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint[$this->environment] . 'identity/oauth2/userinfo?schema=paypalv1.1',
|
||||
$this->resourceEndpoint[$this->environment].'identity/oauth2/userinfo?schema=paypalv1.1',
|
||||
$header
|
||||
);
|
||||
$this->user = \json_decode($user, true);
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Paypal;
|
||||
|
||||
class PaypalSandbox extends Paypal
|
||||
{
|
||||
protected string $environment = 'sandbox';
|
||||
|
||||
@@ -51,19 +51,18 @@ class Podio extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . '/authorize?' .
|
||||
$url = $this->endpoint.'/authorize?'.
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback
|
||||
'redirect_uri' => $this->callback,
|
||||
]);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -71,14 +70,14 @@ class Podio extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->apiEndpoint . '/oauth/token',
|
||||
$this->apiEndpoint.'/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret
|
||||
'client_secret' => $this->appSecret,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -87,15 +86,14 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->apiEndpoint . '/oauth/token',
|
||||
$this->apiEndpoint.'/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -113,8 +111,7 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -125,8 +122,7 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -139,8 +135,7 @@ class Podio extends OAuth2
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -148,7 +143,7 @@ class Podio extends OAuth2
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
$mails = $user['mails'];
|
||||
$mainMailIndex = \array_search($user['mail'], \array_map(fn($m) => $m['mail'], $mails));
|
||||
$mainMailIndex = \array_search($user['mail'], \array_map(fn ($m) => $m['mail'], $mails));
|
||||
$mainMain = $mails[$mainMailIndex];
|
||||
|
||||
if ($mainMain['verified'] ?? false) {
|
||||
@@ -159,8 +154,7 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -171,8 +165,7 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -180,14 +173,14 @@ class Podio extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = \json_decode($this->request(
|
||||
'GET',
|
||||
$this->apiEndpoint . '/user',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
$this->apiEndpoint.'/user',
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
), true);
|
||||
|
||||
$profile = \json_decode($this->request(
|
||||
'GET',
|
||||
$this->apiEndpoint . '/user/profile',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
$this->apiEndpoint.'/user/profile',
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
), true);
|
||||
|
||||
$this->user = $user;
|
||||
|
||||
@@ -25,7 +25,7 @@ class Salesforce extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"openid"
|
||||
'openid',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -37,8 +37,7 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*
|
||||
* @param string $state
|
||||
* @return array
|
||||
*/
|
||||
public function parseState(string $state)
|
||||
@@ -46,31 +45,29 @@ class Salesforce extends OAuth2
|
||||
return \json_decode(\html_entity_decode($state), true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://login.salesforce.com/services/oauth2/authorize?' . \http_build_query([
|
||||
return 'https://login.salesforce.com/services/oauth2/authorize?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if (empty($this->tokens)) {
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret),
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
@@ -80,7 +77,7 @@ class Salesforce extends OAuth2
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->callback,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -89,14 +86,13 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret),
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
@@ -105,7 +101,7 @@ class Salesforce extends OAuth2
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -117,8 +113,7 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -129,8 +124,7 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -145,8 +139,7 @@ class Salesforce extends OAuth2
|
||||
*
|
||||
* @link https://help.salesforce.com/s/articleView?id=sf.remoteaccess_using_userinfo_endpoint.htm&type=5
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -161,8 +154,7 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -173,16 +165,16 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class Slack extends OAuth2
|
||||
'identity.avatar',
|
||||
'identity.basic',
|
||||
'identity.email',
|
||||
'identity.team'
|
||||
'identity.team',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -40,17 +40,16 @@ class Slack extends OAuth2
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
// https://api.slack.com/docs/oauth#step_1_-_sending_users_to_authorize_and_or_install
|
||||
return 'https://slack.com/oauth/authorize?' . \http_build_query([
|
||||
return 'https://slack.com/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -59,11 +58,11 @@ class Slack extends OAuth2
|
||||
// https://api.slack.com/docs/oauth#step_3_-_exchanging_a_verification_code_for_an_access_token
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://slack.com/api/oauth.access?' . \http_build_query([
|
||||
'https://slack.com/api/oauth.access?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->callback
|
||||
'redirect_uri' => $this->callback,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -72,19 +71,18 @@ class Slack extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://slack.com/api/oauth.access?' . \http_build_query([
|
||||
'https://slack.com/api/oauth.access?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -96,8 +94,7 @@ class Slack extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -108,8 +105,7 @@ class Slack extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -126,20 +122,18 @@ class Slack extends OAuth2
|
||||
*
|
||||
* @link https://slack.com/help/articles/207262907-Change-your-email-address
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -152,8 +146,7 @@ class Slack extends OAuth2
|
||||
/**
|
||||
* @link https://api.slack.com/methods/users.identity
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -161,7 +154,7 @@ class Slack extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
'https://slack.com/api/users.identity?token=' . \urlencode($accessToken)
|
||||
'https://slack.com/api/users.identity?token='.\urlencode($accessToken)
|
||||
);
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
|
||||
@@ -49,33 +49,32 @@ class Spotify extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'authorize?' .
|
||||
return $this->endpoint.'authorize?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'api/token',
|
||||
$this->endpoint.'api/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"code" => $code,
|
||||
"grant_type" => "authorization_code",
|
||||
"redirect_uri" => $this->callback
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
'redirect_uri' => $this->callback,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -84,20 +83,19 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'api/token',
|
||||
$this->endpoint.'api/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"refresh_token" => $refreshToken,
|
||||
"grant_type" => "refresh_token",
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -109,8 +107,7 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -121,8 +118,7 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -139,8 +135,7 @@ class Spotify extends OAuth2
|
||||
*
|
||||
* @link https://developer.spotify.com/documentation/web-api/reference/#/operations/get-current-users-profile
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -149,8 +144,7 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -161,8 +155,7 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
@@ -170,8 +163,8 @@ class Spotify extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint . 'me',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
$this->resourceEndpoint.'me',
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Exception;
|
||||
|
||||
class Stripe extends OAuth2
|
||||
{
|
||||
@@ -50,18 +49,17 @@ class Stripe extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://connect.stripe.com/oauth/authorize?' . \http_build_query([
|
||||
return 'https://connect.stripe.com/oauth/authorize?'.\http_build_query([
|
||||
'response_type' => 'code', // The only option at the moment is "code."
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -73,7 +71,7 @@ class Stripe extends OAuth2
|
||||
[],
|
||||
\http_build_query([
|
||||
'grant_type' => $this->grantType['authorize'],
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -84,8 +82,7 @@ class Stripe extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -105,12 +102,12 @@ class Stripe extends OAuth2
|
||||
}
|
||||
|
||||
$this->stripeAccountId = $this->tokens['stripe_user_id'];
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -121,8 +118,7 @@ class Stripe extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -141,20 +137,18 @@ class Stripe extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Stripe sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -165,18 +159,17 @@ class Stripe extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user) && !empty($this->stripeAccountId)) {
|
||||
if (empty($this->user) && ! empty($this->stripeAccountId)) {
|
||||
$this->user = \json_decode(
|
||||
$this->request(
|
||||
'GET',
|
||||
'https://api.stripe.com/v1/accounts/' . $this->stripeAccountId,
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
'https://api.stripe.com/v1/accounts/'.$this->stripeAccountId,
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
@@ -10,6 +10,7 @@ use Appwrite\Auth\OAuth2;
|
||||
class Tradeshift extends OAuth2
|
||||
{
|
||||
public const TRADESHIFT_SANDBOX_API_DOMAIN = 'api-sandbox.tradeshift.com';
|
||||
|
||||
public const TRADESHIFT_API_DOMAIN = 'api.tradeshift.com';
|
||||
|
||||
private array $apiDomain = [
|
||||
@@ -18,13 +19,13 @@ class Tradeshift extends OAuth2
|
||||
];
|
||||
|
||||
private array $endpoint = [
|
||||
'sandbox' => 'https://' . self::TRADESHIFT_SANDBOX_API_DOMAIN . '/tradeshift/',
|
||||
'live' => 'https://' . self::TRADESHIFT_API_DOMAIN . '/tradeshift/',
|
||||
'sandbox' => 'https://'.self::TRADESHIFT_SANDBOX_API_DOMAIN.'/tradeshift/',
|
||||
'live' => 'https://'.self::TRADESHIFT_API_DOMAIN.'/tradeshift/',
|
||||
];
|
||||
|
||||
private array $resourceEndpoint = [
|
||||
'sandbox' => 'https://' . self::TRADESHIFT_SANDBOX_API_DOMAIN . '/tradeshift/rest/external/',
|
||||
'live' => 'https://' . self::TRADESHIFT_API_DOMAIN . '/tradeshift/rest/external/',
|
||||
'sandbox' => 'https://'.self::TRADESHIFT_SANDBOX_API_DOMAIN.'/tradeshift/rest/external/',
|
||||
'live' => 'https://'.self::TRADESHIFT_API_DOMAIN.'/tradeshift/rest/external/',
|
||||
];
|
||||
|
||||
protected string $environment = 'live';
|
||||
@@ -64,18 +65,17 @@ class Tradeshift extends OAuth2
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => \str_replace("localhost", "127.0.0.1", $this->callback),
|
||||
'redirect_uri' => \str_replace('localhost', '127.0.0.1', $this->callback),
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
|
||||
$url = $this->endpoint[$this->environment] . 'auth/login?' . $httpQuery;
|
||||
$url = $this->endpoint[$this->environment].'auth/login?'.$httpQuery;
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -83,8 +83,8 @@ class Tradeshift extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint[$this->environment] . 'auth/token',
|
||||
['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)],
|
||||
$this->endpoint[$this->environment].'auth/token',
|
||||
['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $code,
|
||||
@@ -96,16 +96,15 @@ class Tradeshift extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint[$this->environment] . 'auth/token',
|
||||
['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)],
|
||||
$this->endpoint[$this->environment].'auth/token',
|
||||
['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken,
|
||||
@@ -120,8 +119,7 @@ class Tradeshift extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -132,8 +130,7 @@ class Tradeshift extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -148,20 +145,18 @@ class Tradeshift extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Tradeshift sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUser($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -171,12 +166,11 @@ class Tradeshift extends OAuth2
|
||||
$firstName = $user['FirstName'] ?? '';
|
||||
$lastName = $user['LastName'] ?? '';
|
||||
|
||||
return $firstName . ' ' . $lastName;
|
||||
return $firstName.' '.$lastName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -184,14 +178,14 @@ class Tradeshift extends OAuth2
|
||||
$header = [
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'Host: ' . urlencode($this->apiDomain[$this->environment]),
|
||||
'Authorization: Bearer ' . $accessToken,
|
||||
'Host: '.urlencode($this->apiDomain[$this->environment]),
|
||||
'Authorization: Bearer '.$accessToken,
|
||||
];
|
||||
|
||||
if (empty($this->user)) {
|
||||
$response = $this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint[$this->environment] . 'account/info/user',
|
||||
$this->resourceEndpoint[$this->environment].'account/info/user',
|
||||
$header
|
||||
);
|
||||
$this->user = \json_decode($response, true);
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Tradeshift;
|
||||
|
||||
class TradeshiftBox extends Tradeshift
|
||||
{
|
||||
protected string $environment = 'sandbox';
|
||||
|
||||
@@ -49,20 +49,19 @@ class Twitch extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'authorize?' .
|
||||
return $this->endpoint.'authorize?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback,
|
||||
'force_verify' => true,
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -70,12 +69,12 @@ class Twitch extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'token?' . \http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"code" => $code,
|
||||
"grant_type" => "authorization_code",
|
||||
"redirect_uri" => $this->callback
|
||||
$this->endpoint.'token?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
'redirect_uri' => $this->callback,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -84,19 +83,18 @@ class Twitch extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'token?' . \http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"refresh_token" => $refreshToken,
|
||||
"grant_type" => "refresh_token",
|
||||
$this->endpoint.'token?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -108,8 +106,7 @@ class Twitch extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -120,8 +117,7 @@ class Twitch extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -138,20 +134,18 @@ class Twitch extends OAuth2
|
||||
*
|
||||
* @link https://dev.twitch.tv/docs/api/reference#get-users
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -162,8 +156,7 @@ class Twitch extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
@@ -173,8 +166,8 @@ class Twitch extends OAuth2
|
||||
'GET',
|
||||
$this->resourceEndpoint,
|
||||
[
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Client-Id: ' . \urlencode($this->appID)
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Client-Id: '.\urlencode($this->appID),
|
||||
]
|
||||
), true);
|
||||
|
||||
|
||||
@@ -39,18 +39,17 @@ class WordPress extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://public-api.wordpress.com/oauth2/authorize?' . \http_build_query([
|
||||
return 'https://public-api.wordpress.com/oauth2/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code',
|
||||
'scope' => $this->getScopes(),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -65,7 +64,7 @@ class WordPress extends OAuth2
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -74,8 +73,7 @@ class WordPress extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -88,7 +86,7 @@ class WordPress extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken
|
||||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -100,8 +98,7 @@ class WordPress extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -112,8 +109,7 @@ class WordPress extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -132,8 +128,7 @@ class WordPress extends OAuth2
|
||||
*
|
||||
* @link https://developer.wordpress.com/docs/api/1.1/get/me/
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -148,8 +143,7 @@ class WordPress extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -160,14 +154,13 @@ class WordPress extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', 'https://public-api.wordpress.com/rest/v1/me', ['Authorization: Bearer ' . $accessToken]), true);
|
||||
$this->user = \json_decode($this->request('GET', 'https://public-api.wordpress.com/rest/v1/me', ['Authorization: Bearer '.$accessToken]), true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
||||
@@ -45,10 +45,8 @@ class Yahoo extends OAuth2
|
||||
return 'yahoo';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parseState(string $state)
|
||||
@@ -61,37 +59,36 @@ class Yahoo extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'request_auth?' .
|
||||
return $this->endpoint.'request_auth?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if (empty($this->tokens)) {
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret),
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'get_token',
|
||||
$this->endpoint.'get_token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"code" => $code,
|
||||
"grant_type" => "authorization_code",
|
||||
"redirect_uri" => $this->callback
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
'redirect_uri' => $this->callback,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -100,24 +97,23 @@ class Yahoo extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret),
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'get_token',
|
||||
$this->endpoint.'get_token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"refresh_token" => $refreshToken,
|
||||
"grant_type" => "refresh_token",
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -129,8 +125,7 @@ class Yahoo extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -141,8 +136,7 @@ class Yahoo extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -157,20 +151,18 @@ class Yahoo extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Yahoo sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -181,8 +173,7 @@ class Yahoo extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
@@ -191,7 +182,7 @@ class Yahoo extends OAuth2
|
||||
$this->user = \json_decode($this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint,
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
), true);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user