Merge pull request #1266 from appwrite/feat-db-refactor-routes
Feat - Appwrite Database using Utopia\Database
This commit is contained in:
commit
19e9a138e4
|
@ -212,6 +212,7 @@ RUN chmod +x /usr/local/bin/doctor && \
|
|||
chmod +x /usr/local/bin/vars && \
|
||||
chmod +x /usr/local/bin/worker-audits && \
|
||||
chmod +x /usr/local/bin/worker-certificates && \
|
||||
chmod +x /usr/local/bin/worker-database && \
|
||||
chmod +x /usr/local/bin/worker-deletes && \
|
||||
chmod +x /usr/local/bin/worker-functions && \
|
||||
chmod +x /usr/local/bin/worker-mails && \
|
||||
|
|
|
@ -19,6 +19,7 @@ $collections = [
|
|||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -29,6 +30,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -39,6 +41,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -49,6 +52,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -59,6 +63,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -69,6 +74,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -79,6 +85,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -89,6 +96,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -99,6 +107,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -109,6 +118,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -119,6 +129,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -129,6 +140,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -139,6 +151,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
|
@ -149,6 +162,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
|
@ -159,6 +173,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
|
@ -169,6 +184,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
|
@ -179,6 +195,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
|
@ -206,6 +223,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -216,6 +234,7 @@ $collections = [
|
|||
'size' => 1024,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -226,6 +245,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -236,6 +256,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -246,6 +267,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -256,6 +278,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['json']
|
||||
],
|
||||
|
@ -266,6 +289,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -276,6 +300,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -286,6 +311,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -296,6 +322,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
|
@ -306,6 +333,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
|
@ -316,6 +344,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
|
@ -343,6 +372,7 @@ $collections = [
|
|||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -353,6 +383,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -363,6 +394,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -390,6 +422,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -400,6 +433,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -410,6 +444,7 @@ $collections = [
|
|||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -420,6 +455,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -430,6 +466,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -440,6 +477,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -450,6 +488,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -491,6 +530,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -502,6 +542,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -512,6 +553,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -522,6 +564,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -532,6 +575,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -542,6 +586,7 @@ $collections = [
|
|||
'size' => 127, // https://tools.ietf.org/html/rfc4288#section-4.2
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -552,6 +597,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -562,6 +608,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -572,6 +619,7 @@ $collections = [
|
|||
'size' => 255,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -582,6 +630,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -592,6 +641,7 @@ $collections = [
|
|||
'size' => 64,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -602,6 +652,7 @@ $collections = [
|
|||
'size' => 64,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -612,6 +663,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -622,6 +674,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -656,6 +709,7 @@ $collections = [
|
|||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -666,6 +720,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -676,6 +731,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -687,6 +743,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -697,6 +754,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -707,6 +765,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -717,6 +776,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -727,6 +787,7 @@ $collections = [
|
|||
'size' => 8192,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['json', 'encrypt'],
|
||||
],
|
||||
|
@ -737,6 +798,7 @@ $collections = [
|
|||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -747,6 +809,7 @@ $collections = [
|
|||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -757,6 +820,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -767,6 +831,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -777,6 +842,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -804,6 +870,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -814,6 +881,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -825,6 +893,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -835,6 +904,7 @@ $collections = [
|
|||
'size' => 2048,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -845,6 +915,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -872,6 +943,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -882,6 +954,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -892,6 +965,7 @@ $collections = [
|
|||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -903,6 +977,7 @@ $collections = [
|
|||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -913,6 +988,7 @@ $collections = [
|
|||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -923,6 +999,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -933,6 +1010,7 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -943,6 +1021,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -953,6 +1032,7 @@ $collections = [
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
|
@ -967,6 +1047,91 @@ $collections = [
|
|||
]
|
||||
],
|
||||
],
|
||||
'certificates' => [
|
||||
'$collection' => Database::COLLECTIONS,
|
||||
'$id' => 'certificates',
|
||||
'name' => 'Certificates',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'domain',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
// The maximum total length of a domain name or number is 255 characters.
|
||||
// https://datatracker.ietf.org/doc/html/rfc2821#section-4.5.3.1
|
||||
// https://datatracker.ietf.org/doc/html/rfc5321#section-4.5.3.1.2
|
||||
'size' => 255,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'issueDate',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'renewDate',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'attempts',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'log',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'updated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_domain',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['domain'],
|
||||
'lengths' => [255],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
/*
|
||||
|
@ -984,6 +1149,7 @@ foreach ($providers as $index => $provider) {
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
];
|
||||
|
@ -995,6 +1161,7 @@ foreach ($providers as $index => $provider) {
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
];
|
||||
|
@ -1008,6 +1175,7 @@ foreach ($auth as $index => $method) {
|
|||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
];
|
||||
|
|
|
@ -82,6 +82,26 @@ return [
|
|||
'model' => Response::MODEL_COLLECTION,
|
||||
'note' => '',
|
||||
],
|
||||
'database.attributes.create' => [
|
||||
'description' => 'This event triggers when a collection attribute is created.',
|
||||
'model' => Response::MODEL_ATTRIBUTE,
|
||||
'note' => '',
|
||||
],
|
||||
'database.attributes.delete' => [
|
||||
'description' => 'This event triggers when a collection attribute is deleted.',
|
||||
'model' => Response::MODEL_ATTRIBUTE,
|
||||
'note' => '',
|
||||
],
|
||||
'database.indexes.create' => [
|
||||
'description' => 'This event triggers when a collection index is created.',
|
||||
'model' => Response::MODEL_INDEX,
|
||||
'note' => '',
|
||||
],
|
||||
'database.indexes.delete' => [
|
||||
'description' => 'This event triggers when a collection index is deleted.',
|
||||
'model' => Response::MODEL_INDEX,
|
||||
'note' => '',
|
||||
],
|
||||
'database.documents.create' => [
|
||||
'description' => 'This event triggers when a database document is created.',
|
||||
'model' => Response::MODEL_DOCUMENT,
|
||||
|
|
|
@ -32,6 +32,10 @@ $admins = [
|
|||
'users.write',
|
||||
'collections.read',
|
||||
'collections.write',
|
||||
'attributes.read',
|
||||
'attributes.write',
|
||||
'indexes.read',
|
||||
'indexes.write',
|
||||
'platforms.read',
|
||||
'platforms.write',
|
||||
'keys.read',
|
||||
|
|
|
@ -19,6 +19,18 @@ return [ // List of publicly visible scopes
|
|||
'collections.write' => [
|
||||
'description' => 'Access to create, update, and delete your project\'s database collections',
|
||||
],
|
||||
'attributes.read' => [
|
||||
'description' => 'Access to read your project\'s database collection\'s attributes',
|
||||
],
|
||||
'attributes.write' => [
|
||||
'description' => 'Access to create, update, and delete your project\'s database collection\'s attributes',
|
||||
],
|
||||
'indexes.read' => [
|
||||
'description' => 'Access to read your project\'s database collection\'s indexes',
|
||||
],
|
||||
'indexes.write' => [
|
||||
'description' => 'Access to create, update, and delete your project\'s database collection\'s indexes',
|
||||
],
|
||||
'documents.read' => [
|
||||
'description' => 'Access to read your project\'s database documents',
|
||||
],
|
||||
|
|
|
@ -858,7 +858,6 @@ App::get('/v1/account/logs')
|
|||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
$audit = new Audit($dbForInternal);
|
||||
|
||||
$countries = $locale->getText('countries');
|
||||
|
||||
$logs = $audit->getLogsByUserAndEvents($user->getId(), [
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1006,6 +1006,7 @@ App::post('/v1/projects/:projectId/tasks')
|
|||
|
||||
$task = new Document([
|
||||
'$id' => $dbForConsole->getId(),
|
||||
'projectId' => $project->getId(),
|
||||
'name' => $name,
|
||||
'status' => $status,
|
||||
'schedule' => $schedule,
|
||||
|
|
|
@ -222,8 +222,7 @@ App::get('/v1/users/:userId/logs')
|
|||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var MaxMind\Db\Reader $geodb */
|
||||
/** @var Utopia\App $app */
|
||||
|
||||
|
||||
$user = $dbForInternal->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
|
|
|
@ -16,17 +16,19 @@ use Appwrite\Utopia\Response\Filters\V06;
|
|||
use Appwrite\Utopia\Response\Filters\V07;
|
||||
use Appwrite\Utopia\Response\Filters\V08;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization as Authorization2;
|
||||
|
||||
Config::setParam('domainVerification', false);
|
||||
Config::setParam('cookieDomain', 'localhost');
|
||||
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
|
||||
|
||||
App::init(function ($utopia, $request, $response, $console, $project, $consoleDB, $user, $locale, $clients) {
|
||||
App::init(function ($utopia, $request, $response, $console, $project, $dbForConsole, $user, $locale, $clients) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $consoleDB */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var Utopia\Database\Document $console */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
|
@ -42,36 +44,29 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
|
|||
$domains[$domain->get()] = false;
|
||||
Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
||||
} else {
|
||||
Authorization::disable();
|
||||
$dbDomain = $consoleDB->getCollectionFirst([
|
||||
'limit' => 1,
|
||||
'offset' => 0,
|
||||
'filters' => [
|
||||
'$collection=' . Database::SYSTEM_COLLECTION_CERTIFICATES,
|
||||
'domain=' . $domain->get(),
|
||||
],
|
||||
]);
|
||||
Authorization2::disable();
|
||||
|
||||
if (empty($dbDomain)) {
|
||||
$dbDomain = [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_CERTIFICATES,
|
||||
'$permissions' => [
|
||||
'read' => [],
|
||||
'write' => [],
|
||||
],
|
||||
$certificate = $dbForConsole->findFirst('certificates', [
|
||||
new Query('domain', QUERY::TYPE_EQUAL, [$domain->get()])
|
||||
], /*limit*/ 1);
|
||||
|
||||
if (empty($certificate)) {
|
||||
$certificate = new Document([
|
||||
'domain' => $domain->get(),
|
||||
];
|
||||
$dbDomain = $consoleDB->createDocument($dbDomain);
|
||||
Authorization::enable();
|
||||
]);
|
||||
$certificate = $dbForConsole->createDocument('certificates', $certificate);
|
||||
Authorization2::enable();
|
||||
|
||||
Console::info('Issuing a TLS certificate for the master domain (' . $domain->get() . ') in a few seconds...'); // TODO move this to installation script
|
||||
|
||||
Resque::enqueue('v1-certificates', 'CertificatesV1', [
|
||||
'document' => $dbDomain,
|
||||
'document' => $certificate,
|
||||
'domain' => $domain->get(),
|
||||
'validateTarget' => false,
|
||||
'validateCNAME' => false,
|
||||
]);
|
||||
} else {
|
||||
Authorization2::enable(); // ensure authorization is reenabled
|
||||
}
|
||||
$domains[$domain->get()] = true;
|
||||
}
|
||||
|
@ -286,7 +281,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
|
|||
throw new Exception('Password reset is required', 412);
|
||||
}
|
||||
|
||||
}, ['utopia', 'request', 'response', 'console', 'project', 'consoleDB', 'user', 'locale', 'clients']);
|
||||
}, ['utopia', 'request', 'response', 'console', 'project', 'dbForConsole', 'user', 'locale', 'clients']);
|
||||
|
||||
App::options(function ($request, $response) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
|
|
|
@ -9,7 +9,7 @@ use Utopia\Abuse\Adapters\TimeLimit;
|
|||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Storage;
|
||||
|
||||
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes, $dbForInternal) {
|
||||
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes, $database, $dbForInternal) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
|
@ -20,6 +20,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
|
|||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Event\Event $database */
|
||||
/** @var Appwrite\Event\Event $functions */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
|
@ -36,7 +37,6 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
|
|||
* Abuse Check
|
||||
*/
|
||||
$timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForInternal);
|
||||
|
||||
$timeLimit
|
||||
->setParam('{userId}', $user->getId())
|
||||
->setParam('{userAgent}', $request->getUserAgent(''))
|
||||
|
@ -110,7 +110,11 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
|
|||
->setParam('projectId', $project->getId())
|
||||
;
|
||||
|
||||
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes', 'dbForInternal'], 'api');
|
||||
$database
|
||||
->setParam('projectId', $project->getId())
|
||||
;
|
||||
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes', 'database', 'dbForInternal'], 'api');
|
||||
|
||||
|
||||
App::init(function ($utopia, $request, $response, $project, $user) {
|
||||
/** @var Utopia\App $utopia */
|
||||
|
@ -166,7 +170,7 @@ App::init(function ($utopia, $request, $response, $project, $user) {
|
|||
|
||||
}, ['utopia', 'request', 'response', 'project', 'user'], 'auth');
|
||||
|
||||
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $mode) {
|
||||
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $database, $mode) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
|
@ -175,6 +179,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
|||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Event\Event $database */
|
||||
/** @var Appwrite\Event\Event $functions */
|
||||
/** @var bool $mode */
|
||||
|
||||
|
@ -204,6 +209,10 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
|||
if (!empty($deletes->getParam('type')) && !empty($deletes->getParam('document'))) {
|
||||
$deletes->trigger();
|
||||
}
|
||||
|
||||
if (!empty($database->getParam('type')) && !empty($database->getParam('document'))) {
|
||||
$database->trigger();
|
||||
}
|
||||
|
||||
$route = $utopia->match($request);
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled'
|
||||
|
@ -218,4 +227,4 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
|||
;
|
||||
}
|
||||
|
||||
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'mode'], 'api');
|
||||
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'database', 'mode'], 'api');
|
||||
|
|
11
app/http.php
11
app/http.php
|
@ -54,14 +54,6 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
$app = new App('UTC');
|
||||
|
||||
go(function() use ($register, $app) {
|
||||
// Only retry connection once before throwing exception
|
||||
try {
|
||||
$db = $register->get('dbPool')->get();
|
||||
} catch (\Exception $exception) {
|
||||
Console::warning('[Setup] - Database not ready. Waiting for five seconds...');
|
||||
sleep(5);
|
||||
}
|
||||
|
||||
$db = $register->get('dbPool')->get();
|
||||
$redis = $register->get('redisPool')->get();
|
||||
|
||||
|
@ -77,6 +69,9 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
|||
return $app;
|
||||
});
|
||||
|
||||
// wait for database to be ready
|
||||
sleep(5);
|
||||
|
||||
$dbForConsole = $app->getResource('dbForConsole'); /** @var Utopia\Database\Database $dbForConsole */
|
||||
|
||||
if(!$dbForConsole->exists()) {
|
||||
|
|
|
@ -72,7 +72,12 @@ const APP_SOCIAL_DISCORD = 'https://appwrite.io/discord';
|
|||
const APP_SOCIAL_DISCORD_CHANNEL = '564160730845151244';
|
||||
const APP_SOCIAL_DEV = 'https://dev.to/appwrite';
|
||||
const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite';
|
||||
// Creation Types
|
||||
const CREATE_TYPE_ATTRIBUTE = 'newAttribute';
|
||||
const CREATE_TYPE_INDEX = 'newIndex';
|
||||
// Deletion Types
|
||||
const DELETE_TYPE_ATTRIBUTE = 'attribute';
|
||||
const DELETE_TYPE_INDEX = 'index';
|
||||
const DELETE_TYPE_DOCUMENT = 'document';
|
||||
const DELETE_TYPE_EXECUTIONS = 'executions';
|
||||
const DELETE_TYPE_AUDIT = 'audit';
|
||||
|
@ -386,6 +391,10 @@ App::setResource('deletes', function($register) {
|
|||
return new Event(Event::DELETE_QUEUE_NAME, Event::DELETE_CLASS_NAME);
|
||||
}, ['register']);
|
||||
|
||||
App::setResource('database', function($register) {
|
||||
return new Event(Event::DATABASE_QUEUE_NAME, Event::DATABASE_CLASS_NAME);
|
||||
}, ['register']);
|
||||
|
||||
// Test Mock
|
||||
App::setResource('clients', function($request, $console, $project) {
|
||||
$console->setAttribute('platforms', [ // Allways allow current host
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
||||
use Appwrite\Database\Adapter\Redis as RedisAdapter;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Appwrite\Network\Validator\CNAME;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Redis;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Domains\Domain;
|
||||
|
||||
require_once __DIR__.'/../workers.php';
|
||||
|
@ -28,183 +30,178 @@ class CertificatesV1 extends Worker
|
|||
{
|
||||
global $register;
|
||||
|
||||
$db = $register->get('db');
|
||||
$cache = $register->get('cache');
|
||||
go(function() use ($register) {
|
||||
$db = $register->get('dbPool')->get();
|
||||
$redis = $register->get('redisPool')->get();
|
||||
|
||||
$consoleDB = new Database();
|
||||
$consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
|
||||
$consoleDB->setNamespace('app_console'); // Main DB
|
||||
$consoleDB->setMocks(Config::getParam('collections', []));
|
||||
$cache = new Cache(new Redis($redis));
|
||||
$dbForConsole = new Database(new MariaDB($db), $cache);
|
||||
$dbForConsole->setNamespace('project_console_internal');
|
||||
|
||||
/**
|
||||
* 1. Get new domain document - DONE
|
||||
* 1.1. Validate domain is valid, public suffix is known and CNAME records are verified - DONE
|
||||
* 2. Check if a certificate already exists - DONE
|
||||
* 3. Check if certificate is about to expire, if not - skip it
|
||||
* 3.1. Create / renew certificate
|
||||
* 3.2. Update loadblancer
|
||||
* 3.3. Update database (domains, change date, expiry)
|
||||
* 3.4. Set retry on failure
|
||||
* 3.5. Schedule to renew certificate in 60 days
|
||||
*/
|
||||
/**
|
||||
* 1. Get new domain document - DONE
|
||||
* 1.1. Validate domain is valid, public suffix is known and CNAME records are verified - DONE
|
||||
* 2. Check if a certificate already exists - DONE
|
||||
* 3. Check if certificate is about to expire, if not - skip it
|
||||
* 3.1. Create / renew certificate
|
||||
* 3.2. Update loadblancer
|
||||
* 3.3. Update database (domains, change date, expiry)
|
||||
* 3.4. Set retry on failure
|
||||
* 3.5. Schedule to renew certificate in 60 days
|
||||
*/
|
||||
|
||||
Authorization::disable();
|
||||
Authorization::disable();
|
||||
|
||||
// Args
|
||||
$document = $this->args['document'];
|
||||
$domain = $this->args['domain'];
|
||||
// Args
|
||||
$document = $this->args['document'];
|
||||
$domain = $this->args['domain'];
|
||||
|
||||
// Validation Args
|
||||
$validateTarget = $this->args['validateTarget'] ?? true;
|
||||
$validateCNAME = $this->args['validateCNAME'] ?? true;
|
||||
// Validation Args
|
||||
$validateTarget = $this->args['validateTarget'] ?? true;
|
||||
$validateCNAME = $this->args['validateCNAME'] ?? true;
|
||||
|
||||
// Options
|
||||
$domain = new Domain((!empty($domain)) ? $domain : '');
|
||||
$expiry = 60 * 60 * 24 * 30 * 2; // 60 days
|
||||
$safety = 60 * 60; // 1 hour
|
||||
$renew = (\time() + $expiry);
|
||||
|
||||
if(empty($domain->get())) {
|
||||
throw new Exception('Missing domain');
|
||||
}
|
||||
|
||||
if(!$domain->isKnown() || $domain->isTest()) {
|
||||
throw new Exception('Unknown public suffix for domain');
|
||||
}
|
||||
|
||||
if($validateTarget) {
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
// Options
|
||||
$domain = new Domain((!empty($domain)) ? $domain : '');
|
||||
$expiry = 60 * 60 * 24 * 30 * 2; // 60 days
|
||||
$safety = 60 * 60; // 1 hour
|
||||
$renew = (\time() + $expiry);
|
||||
|
||||
if(empty($domain->get())) {
|
||||
throw new Exception('Missing domain');
|
||||
}
|
||||
|
||||
if(!$domain->isKnown() || $domain->isTest()) {
|
||||
throw new Exception('Unknown public suffix for domain');
|
||||
}
|
||||
|
||||
if($validateTarget) {
|
||||
$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.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($validateCNAME) {
|
||||
$validator = new CNAME($target->get()); // Verify Domain with DNS records
|
||||
|
||||
if(!$validator->isValid($domain->get())) {
|
||||
throw new Exception('Failed to verify domain DNS records');
|
||||
}
|
||||
}
|
||||
|
||||
$certificate = $consoleDB->getCollectionFirst([
|
||||
'limit' => 1,
|
||||
'offset' => 0,
|
||||
'filters' => [
|
||||
'$collection='.Database::SYSTEM_COLLECTION_CERTIFICATES,
|
||||
'domain='.$domain->get(),
|
||||
],
|
||||
]);
|
||||
|
||||
// $condition = ($certificate
|
||||
// && $certificate instanceof Document
|
||||
// && isset($certificate['issueDate'])
|
||||
// && (($certificate['issueDate'] + ($expiry)) > time())) ? 'true' : 'false';
|
||||
|
||||
// throw new Exception('cert issued at'.date('d.m.Y H:i', $certificate['issueDate']).' | renew date is: '.date('d.m.Y H:i', ($certificate['issueDate'] + ($expiry))).' | condition is '.$condition);
|
||||
|
||||
$certificate = (!empty($certificate) && $certificate instanceof $certificate) ? $certificate->getArrayCopy() : [];
|
||||
|
||||
if(!empty($certificate)
|
||||
&& isset($certificate['issueDate'])
|
||||
&& (($certificate['issueDate'] + ($expiry)) > \time())) { // Check last issue time
|
||||
throw new Exception('Renew isn\'t required');
|
||||
}
|
||||
|
||||
$staging = (App::isProduction()) ? '' : ' --dry-run';
|
||||
$email = App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS');
|
||||
|
||||
if(empty($email)) {
|
||||
throw new Exception('You must set a valid security email address (_APP_SYSTEM_SECURITY_EMAIL_ADDRESS) to issue an SSL certificate');
|
||||
}
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}"
|
||||
." --email ".$email
|
||||
." -w ".APP_STORAGE_CERTIFICATES
|
||||
." -d {$domain->get()}", '', $stdout, $stderr);
|
||||
|
||||
if($exit !== 0) {
|
||||
throw new Exception('Failed to issue a certificate with message: '.$stderr);
|
||||
}
|
||||
|
||||
$path = APP_STORAGE_CERTIFICATES.'/'.$domain->get();
|
||||
|
||||
if(!\is_readable($path)) {
|
||||
if (!\mkdir($path, 0755, true)) {
|
||||
throw new Exception('Failed to create path...');
|
||||
}
|
||||
}
|
||||
if($validateCNAME) {
|
||||
$validator = new CNAME($target->get()); // Verify Domain with DNS records
|
||||
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain->get().'/cert.pem', APP_STORAGE_CERTIFICATES.'/'.$domain->get().'/cert.pem')) {
|
||||
throw new Exception('Failed to rename certificate cert.pem: '.\json_encode($stdout));
|
||||
}
|
||||
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain->get().'/chain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain->get().'/chain.pem')) {
|
||||
throw new Exception('Failed to rename certificate chain.pem: '.\json_encode($stdout));
|
||||
}
|
||||
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain->get().'/fullchain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain->get().'/fullchain.pem')) {
|
||||
throw new Exception('Failed to rename certificate fullchain.pem: '.\json_encode($stdout));
|
||||
}
|
||||
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain->get().'/privkey.pem', APP_STORAGE_CERTIFICATES.'/'.$domain->get().'/privkey.pem')) {
|
||||
throw new Exception('Failed to rename certificate privkey.pem: '.\json_encode($stdout));
|
||||
}
|
||||
|
||||
$certificate = \array_merge($certificate, [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_CERTIFICATES,
|
||||
'$permissions' => [
|
||||
'read' => [],
|
||||
'write' => [],
|
||||
],
|
||||
'domain' => $domain->get(),
|
||||
'issueDate' => \time(),
|
||||
'renewDate' => $renew,
|
||||
'attempts' => 0,
|
||||
'log' => \json_encode($stdout),
|
||||
]);
|
||||
|
||||
$certificate = $consoleDB->createDocument($certificate);
|
||||
|
||||
if(!$certificate) {
|
||||
throw new Exception('Failed saving certificate to DB');
|
||||
}
|
||||
|
||||
if(!empty($document)) {
|
||||
$document = \array_merge($document, [
|
||||
'updated' => \time(),
|
||||
'certificateId' => $certificate->getId(),
|
||||
]);
|
||||
|
||||
$document = $consoleDB->updateDocument($document);
|
||||
|
||||
if(!$document) {
|
||||
throw new Exception('Failed saving domain to DB');
|
||||
if(!$validator->isValid($domain->get())) {
|
||||
throw new Exception('Failed to verify domain DNS records');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$certificate = $dbForConsole->findFirst('certificates', [
|
||||
new Query('domain', QUERY::TYPE_EQUAL, [$domain->get()])
|
||||
], /*limit*/ 1);
|
||||
|
||||
// $condition = ($certificate
|
||||
// && $certificate instanceof Document
|
||||
// && isset($certificate['issueDate'])
|
||||
// && (($certificate['issueDate'] + ($expiry)) > time())) ? 'true' : 'false';
|
||||
|
||||
// throw new Exception('cert issued at'.date('d.m.Y H:i', $certificate['issueDate']).' | renew date is: '.date('d.m.Y H:i', ($certificate['issueDate'] + ($expiry))).' | condition is '.$condition);
|
||||
|
||||
$certificate = (!empty($certificate) && $certificate instanceof $certificate) ? $certificate->getArrayCopy() : [];
|
||||
|
||||
if(!empty($certificate)
|
||||
&& isset($certificate['issueDate'])
|
||||
&& (($certificate['issueDate'] + ($expiry)) > \time())) { // Check last issue time
|
||||
throw new Exception('Renew isn\'t required');
|
||||
}
|
||||
|
||||
$staging = (App::isProduction()) ? '' : ' --dry-run';
|
||||
$email = App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS');
|
||||
|
||||
if(empty($email)) {
|
||||
throw new Exception('You must set a valid security email address (_APP_SYSTEM_SECURITY_EMAIL_ADDRESS) to issue an SSL certificate');
|
||||
}
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}"
|
||||
." --email ".$email
|
||||
." -w ".APP_STORAGE_CERTIFICATES
|
||||
." -d {$domain->get()}", '', $stdout, $stderr);
|
||||
|
||||
if($exit !== 0) {
|
||||
throw new Exception('Failed to issue a certificate with message: '.$stderr);
|
||||
}
|
||||
|
||||
$path = APP_STORAGE_CERTIFICATES.'/'.$domain->get();
|
||||
|
||||
if(!\is_readable($path)) {
|
||||
if (!\mkdir($path, 0755, true)) {
|
||||
throw new Exception('Failed to create path...');
|
||||
}
|
||||
}
|
||||
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain->get().'/cert.pem', APP_STORAGE_CERTIFICATES.'/'.$domain->get().'/cert.pem')) {
|
||||
throw new Exception('Failed to rename certificate cert.pem: '.\json_encode($stdout));
|
||||
}
|
||||
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain->get().'/chain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain->get().'/chain.pem')) {
|
||||
throw new Exception('Failed to rename certificate chain.pem: '.\json_encode($stdout));
|
||||
}
|
||||
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain->get().'/fullchain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain->get().'/fullchain.pem')) {
|
||||
throw new Exception('Failed to rename certificate fullchain.pem: '.\json_encode($stdout));
|
||||
}
|
||||
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain->get().'/privkey.pem', APP_STORAGE_CERTIFICATES.'/'.$domain->get().'/privkey.pem')) {
|
||||
throw new Exception('Failed to rename certificate privkey.pem: '.\json_encode($stdout));
|
||||
}
|
||||
|
||||
$certificate = new Document(\array_merge($certificate, [
|
||||
'domain' => $domain->get(),
|
||||
'issueDate' => \time(),
|
||||
'renewDate' => $renew,
|
||||
'attempts' => 0,
|
||||
'log' => \json_encode($stdout),
|
||||
]));
|
||||
|
||||
$certificate = $dbForConsole->createDocument('certificates', $certificate);
|
||||
|
||||
if(!$certificate) {
|
||||
throw new Exception('Failed saving certificate to DB');
|
||||
}
|
||||
|
||||
if(!empty($document)) {
|
||||
$certificate = new Document(\array_merge($document, [
|
||||
'updated' => \time(),
|
||||
'certificateId' => $certificate->getId(),
|
||||
]));
|
||||
|
||||
$config =
|
||||
"tls:
|
||||
certificates:
|
||||
- certFile: /storage/certificates/{$domain->get()}/fullchain.pem
|
||||
keyFile: /storage/certificates/{$domain->get()}/privkey.pem";
|
||||
$certificate = $dbForConsole->updateDocument('certificates', $certificate->getId(), $certificate);
|
||||
|
||||
if(!$certificate) {
|
||||
throw new Exception('Failed saving domain to DB');
|
||||
}
|
||||
}
|
||||
|
||||
$config =
|
||||
"tls:
|
||||
certificates:
|
||||
- certFile: /storage/certificates/{$domain->get()}/fullchain.pem
|
||||
keyFile: /storage/certificates/{$domain->get()}/privkey.pem";
|
||||
|
||||
if(!\file_put_contents(APP_STORAGE_CONFIG.'/'.$domain->get().'.yml', $config)) {
|
||||
throw new Exception('Failed to save SSL configuration');
|
||||
}
|
||||
if(!\file_put_contents(APP_STORAGE_CONFIG.'/'.$domain->get().'.yml', $config)) {
|
||||
throw new Exception('Failed to save SSL configuration');
|
||||
}
|
||||
|
||||
ResqueScheduler::enqueueAt($renew + $safety, 'v1-certificates', 'CertificatesV1', [
|
||||
'document' => [],
|
||||
'domain' => $domain->get(),
|
||||
'validateTarget' => $validateTarget,
|
||||
'validateCNAME' => $validateCNAME,
|
||||
]); // Async task rescheduale
|
||||
ResqueScheduler::enqueueAt($renew + $safety, 'v1-certificates', 'CertificatesV1', [
|
||||
'document' => [],
|
||||
'domain' => $domain->get(),
|
||||
'validateTarget' => $validateTarget,
|
||||
'validateCNAME' => $validateCNAME,
|
||||
]); // Async task rescheduale
|
||||
|
||||
Authorization::reset();
|
||||
Authorization::reset();
|
||||
|
||||
// Return db connections to pool
|
||||
$register->get('dbPool')->put($db);
|
||||
$register->get('redisPool')->put($redis);
|
||||
});
|
||||
}
|
||||
|
||||
public function shutdown(): void
|
||||
|
|
183
app/workers/database.php
Normal file
183
app/workers/database.php
Normal file
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Database V1 Worker');
|
||||
Console::success(APP_NAME.' database worker v1 has started'."\n");
|
||||
|
||||
class DatabaseV1 extends Worker
|
||||
{
|
||||
public $args = [];
|
||||
|
||||
public function init(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$projectId = $this->args['projectId'] ?? '';
|
||||
$type = $this->args['type'] ?? '';
|
||||
|
||||
switch (strval($type)) {
|
||||
case CREATE_TYPE_ATTRIBUTE:
|
||||
$attribute = $this->args['document'] ?? '';
|
||||
$attribute = new Document($attribute);
|
||||
$this->createAttribute($attribute, $projectId);
|
||||
break;
|
||||
case DELETE_TYPE_ATTRIBUTE:
|
||||
$attribute = $this->args['document'] ?? '';
|
||||
$attribute = new Document($attribute);
|
||||
$this->deleteAttribute($attribute, $projectId);
|
||||
break;
|
||||
case CREATE_TYPE_INDEX:
|
||||
$index = $this->args['document'] ?? '';
|
||||
$index = new Document($index);
|
||||
$this->createIndex($index, $projectId);
|
||||
break;
|
||||
case DELETE_TYPE_INDEX:
|
||||
$index = $this->args['document'] ?? '';
|
||||
$index = new Document($index);
|
||||
$this->deleteIndex($index, $projectId);
|
||||
break;
|
||||
|
||||
default:
|
||||
Console::error('No database operation for type: '.$type);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function shutdown(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $attribute
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function createAttribute($attribute, $projectId): void
|
||||
{
|
||||
$dbForExternal = $this->getExternalDB($projectId);
|
||||
|
||||
$collectionId = $attribute->getCollection();
|
||||
$id = $attribute->getAttribute('$id', '');
|
||||
$type = $attribute->getAttribute('type', '');
|
||||
$size = $attribute->getAttribute('size', 0);
|
||||
$required = $attribute->getAttribute('required', false);
|
||||
$default = $attribute->getAttribute('default', null);
|
||||
$signed = $attribute->getAttribute('signed', true);
|
||||
$array = $attribute->getAttribute('array', false);
|
||||
$filters = $attribute->getAttribute('filters', []);
|
||||
|
||||
$success = $dbForExternal->createAttribute($collectionId, $id, $type, $size, $required, $default, $signed, $array, $filters);
|
||||
if ($success) {
|
||||
$removed = $dbForExternal->removeAttributeInQueue($collectionId, $id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $attribute
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteAttribute($attribute, $projectId): void
|
||||
{
|
||||
$dbForExternal = $this->getExternalDB($projectId);
|
||||
|
||||
$collectionId = $attribute->getCollection();
|
||||
$id = $attribute->getAttribute('$id');
|
||||
|
||||
$success = $dbForExternal->deleteAttribute($collectionId, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $index
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function createIndex($index, $projectId): void
|
||||
{
|
||||
$dbForExternal = $this->getExternalDB($projectId);
|
||||
|
||||
$collectionId = $index->getCollection();
|
||||
$id = $index->getAttribute('$id', '');
|
||||
$type = $index->getAttribute('type', '');
|
||||
$attributes = $index->getAttribute('attributes', []);
|
||||
$lengths = $index->getAttribute('lengths', []);
|
||||
$orders = $index->getAttribute('orders', []);
|
||||
|
||||
$success = $dbForExternal->createIndex($collectionId, $id, $type, $attributes, $lengths, $orders);
|
||||
if ($success) {
|
||||
$dbForExternal->removeIndexInQueue($collectionId, $id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $index
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteIndex($index, $projectId): void
|
||||
{
|
||||
$dbForExternal = $this->getExternalDB($projectId);
|
||||
|
||||
$collectionId = $index->getCollection();
|
||||
$id = $index->getAttribute('$id');
|
||||
|
||||
$success = $dbForExternal->deleteIndex($collectionId, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $projectId
|
||||
*
|
||||
* @return Database
|
||||
*/
|
||||
protected function getInternalDB($projectId): Database
|
||||
{
|
||||
global $register;
|
||||
|
||||
$dbForInternal = null;
|
||||
|
||||
go(function() use ($register, $projectId, &$dbForInternal) {
|
||||
$db = $register->get('dbPool')->get();
|
||||
$redis = $register->get('redisPool')->get();
|
||||
|
||||
$cache = new Cache(new RedisCache($redis));
|
||||
$dbForInternal = new Database(new MariaDB($db), $cache);
|
||||
$dbForInternal->setNamespace('project_'.$projectId.'_internal'); // Main DB
|
||||
|
||||
});
|
||||
|
||||
return $dbForInternal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $projectId
|
||||
*
|
||||
* @return Database
|
||||
*/
|
||||
protected function getExternalDB($projectId): Database
|
||||
{
|
||||
global $register;
|
||||
|
||||
/** @var Database $dbForExternal */
|
||||
$dbForExternal = null;
|
||||
|
||||
go(function() use ($register, $projectId, &$dbForExternal) {
|
||||
$db = $register->get('dbPool')->get();
|
||||
$redis = $register->get('redisPool')->get();
|
||||
|
||||
$cache = new Cache(new RedisCache($redis));
|
||||
$dbForExternal = new Database(new MariaDB($db), $cache);
|
||||
$dbForExternal->setNamespace('project_'.$projectId.'_external'); // Main DB
|
||||
|
||||
});
|
||||
|
||||
return $dbForExternal;
|
||||
}
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Database\Database;
|
||||
use Utopia\Database\Database as Database2;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
||||
use Appwrite\Database\Adapter\Redis as RedisAdapter;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Abuse\Abuse;
|
||||
|
@ -43,19 +41,17 @@ class DeletesV1 extends Worker
|
|||
$document = new Document($document);
|
||||
|
||||
switch ($document->getCollection()) {
|
||||
case Database::SYSTEM_COLLECTION_PROJECTS:
|
||||
// TODO@kodumbeats define these as constants somewhere
|
||||
case 'projects':
|
||||
$this->deleteProject($document);
|
||||
break;
|
||||
case Database::SYSTEM_COLLECTION_FUNCTIONS:
|
||||
case 'functions':
|
||||
$this->deleteFunction($document, $projectId);
|
||||
break;
|
||||
case Database::SYSTEM_COLLECTION_USERS:
|
||||
case 'users':
|
||||
$this->deleteUser($document, $projectId);
|
||||
break;
|
||||
case Database::SYSTEM_COLLECTION_COLLECTIONS:
|
||||
$this->deleteDocuments($document, $projectId);
|
||||
break;
|
||||
case Database::SYSTEM_COLLECTION_TEAMS:
|
||||
case 'teams':
|
||||
$this->deleteMemberships($document, $projectId);
|
||||
break;
|
||||
default:
|
||||
|
@ -91,97 +87,91 @@ class DeletesV1 extends Worker
|
|||
{
|
||||
}
|
||||
|
||||
protected function deleteDocuments(Document $document, $projectId)
|
||||
{
|
||||
$collectionId = $document->getId();
|
||||
|
||||
// Delete Documents in the deleted collection
|
||||
$this->deleteByGroup([
|
||||
'$collection='.$collectionId
|
||||
], $this->getProjectDB($projectId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document teams document
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteMemberships(Document $document, $projectId) {
|
||||
$teamId = $document->getAttribute('teamId', '');
|
||||
|
||||
// Delete Memberships
|
||||
$this->deleteByGroup([
|
||||
'$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS,
|
||||
'teamId='.$document->getId(),
|
||||
], $this->getProjectDB($projectId));
|
||||
$this->deleteByGroup('memberships', [
|
||||
new Query('teamId', Query::TYPE_EQUAL, [$teamId])
|
||||
], $this->getInternalDB($projectId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document project document
|
||||
*/
|
||||
protected function deleteProject(Document $document)
|
||||
{
|
||||
$projectId = $document->getId();
|
||||
// Delete all DBs
|
||||
$this->getConsoleDB()->deleteNamespace($document->getId());
|
||||
$this->getExternalDB($projectId)->delete();
|
||||
$this->getInternalDB($projectId)->delete();
|
||||
|
||||
// Delete all storage directories
|
||||
$uploads = new Local(APP_STORAGE_UPLOADS.'/app-'.$document->getId());
|
||||
$cache = new Local(APP_STORAGE_CACHE.'/app-'.$document->getId());
|
||||
|
||||
// Delete all storage directories
|
||||
$uploads->delete($uploads->getRoot(), true);
|
||||
$cache->delete($cache->getRoot(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document user document
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteUser(Document $document, $projectId)
|
||||
{
|
||||
$tokens = $document->getAttribute('tokens', []);
|
||||
|
||||
foreach ($tokens as $token) {
|
||||
if (!$this->getProjectDB($projectId)->deleteDocument($token->getId())) {
|
||||
throw new Exception('Failed to remove token from DB');
|
||||
}
|
||||
}
|
||||
|
||||
$sessions = $document->getAttribute('sessions', []);
|
||||
|
||||
foreach ($sessions as $session) {
|
||||
if (!$this->getProjectDB($projectId)->deleteDocument($session->getId())) {
|
||||
throw new Exception('Failed to remove session from DB');
|
||||
}
|
||||
}
|
||||
$userId = $document->getId();
|
||||
|
||||
// Tokens and Sessions removed with user document
|
||||
// Delete Memberships and decrement team membership counts
|
||||
$this->deleteByGroup([
|
||||
'$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS,
|
||||
'userId='.$document->getId(),
|
||||
], $this->getProjectDB($projectId), function(Document $document) use ($projectId) {
|
||||
$this->deleteByGroup('memberships', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$userId])
|
||||
], $this->getInternalDB($projectId), function(Document $document) use ($projectId, $userId) {
|
||||
|
||||
if ($document->getAttribute('confirm')) { // Count only confirmed members
|
||||
$teamId = $document->getAttribute('teamId');
|
||||
$team = $this->getProjectDB($projectId)->getDocument($teamId);
|
||||
$team = $this->getInternalDB($projectId)->getDocument('teams', $teamId);
|
||||
if(!$team->isEmpty()) {
|
||||
$team = $this->getProjectDB($projectId)->updateDocument(\array_merge($team->getArrayCopy(), [
|
||||
$team = $this->getInternalDB($projectId)->updateDocument('teams', $teamId, new Document(\array_merge($team->getArrayCopy(), [
|
||||
'sum' => \max($team->getAttribute('sum', 0) - 1, 0), // Ensure that sum >= 0
|
||||
]));
|
||||
])));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $timestamp
|
||||
*/
|
||||
protected function deleteExecutionLogs($timestamp)
|
||||
{
|
||||
$this->deleteForProjectIds(function($projectId) use ($timestamp) {
|
||||
if (!($projectDB = $this->getProjectDB($projectId))) {
|
||||
if (!($dbForInternal = $this->getInternalDB($projectId))) {
|
||||
throw new Exception('Failed to get projectDB for project '.$projectId);
|
||||
}
|
||||
|
||||
// Delete Executions
|
||||
$this->deleteByGroup([
|
||||
'$collection='.Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'dateCreated<'.$timestamp
|
||||
], $projectDB);
|
||||
$this->deleteByGroup('executions', [
|
||||
new Query('dateCreated', Query::TYPE_LESSER, [$timestamp])
|
||||
], $dbForInternal);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $timestamp
|
||||
*/
|
||||
protected function deleteAbuseLogs($timestamp)
|
||||
{
|
||||
global $register;
|
||||
if($timestamp == 0) {
|
||||
throw new Exception('Failed to delete audit logs. No timestamp provided');
|
||||
}
|
||||
|
||||
$this->deleteForProjectIds(function($projectId) use ($timestamp){
|
||||
$timeLimit = new TimeLimit("", 0, 1, $this->getInternalDB($projectId));
|
||||
|
||||
$abuse = new Abuse($timeLimit);
|
||||
|
||||
$status = $abuse->cleanup($timestamp);
|
||||
|
@ -191,13 +181,15 @@ class DeletesV1 extends Worker
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $timestamp
|
||||
*/
|
||||
protected function deleteAuditLogs($timestamp)
|
||||
{
|
||||
global $register;
|
||||
if($timestamp == 0) {
|
||||
throw new Exception('Failed to delete audit logs. No timestamp provided');
|
||||
}
|
||||
$this->deleteForProjectIds(function($projectId) use ($register, $timestamp){
|
||||
$this->deleteForProjectIds(function($projectId) use ($timestamp){
|
||||
$audit = new Audit($this->getInternalDB($projectId));
|
||||
$status = $audit->cleanup($timestamp);
|
||||
if (!$status) {
|
||||
|
@ -206,16 +198,19 @@ class DeletesV1 extends Worker
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document function document
|
||||
* @param string $projectId
|
||||
*/
|
||||
protected function deleteFunction(Document $document, $projectId)
|
||||
{
|
||||
$projectDB = $this->getProjectDB($projectId);
|
||||
$dbForInternal = $this->getInternalDB($projectId);
|
||||
$device = new Local(APP_STORAGE_FUNCTIONS.'/app-'.$projectId);
|
||||
|
||||
// Delete Tags
|
||||
$this->deleteByGroup([
|
||||
'$collection='.Database::SYSTEM_COLLECTION_TAGS,
|
||||
'functionId='.$document->getId(),
|
||||
], $projectDB, function(Document $document) use ($device) {
|
||||
$this->deleteByGroup('tags', [
|
||||
new Query('functionId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
], $dbForInternal, function(Document $document) use ($device) {
|
||||
|
||||
if ($device->delete($document->getAttribute('path', ''))) {
|
||||
Console::success('Delete code tag: '.$document->getAttribute('path', ''));
|
||||
|
@ -226,17 +221,25 @@ class DeletesV1 extends Worker
|
|||
});
|
||||
|
||||
// Delete Executions
|
||||
$this->deleteByGroup([
|
||||
'$collection='.Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'functionId='.$document->getId(),
|
||||
], $projectDB);
|
||||
$this->deleteByGroup('executions', [
|
||||
new Query('functionId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
], $dbForInternal);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Document $document to be deleted
|
||||
* @param Database $database to delete it from
|
||||
* @param callable $callback to perform after document is deleted
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function deleteById(Document $document, Database $database, callable $callback = null): bool
|
||||
{
|
||||
Authorization::disable();
|
||||
|
||||
if($database->deleteDocument($document->getId())) {
|
||||
// TODO@kodumbeats is it better to pass objects or ID strings?
|
||||
if($database->deleteDocument($document->getCollection(), $document->getId())) {
|
||||
Console::success('Deleted document "'.$document->getId().'" successfully');
|
||||
|
||||
if(is_callable($callback)) {
|
||||
|
@ -253,6 +256,9 @@ class DeletesV1 extends Worker
|
|||
Authorization::reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callback
|
||||
*/
|
||||
protected function deleteForProjectIds(callable $callback)
|
||||
{
|
||||
$count = 0;
|
||||
|
@ -262,19 +268,12 @@ class DeletesV1 extends Worker
|
|||
$sum = $limit;
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
|
||||
while($sum === $limit) {
|
||||
$chunk++;
|
||||
|
||||
Authorization::disable();
|
||||
$projects = $this->getConsoleDB()->getCollection([
|
||||
'limit' => $limit,
|
||||
'orderType' => 'ASC',
|
||||
'orderCast' => 'string',
|
||||
'filters' => [
|
||||
'$collection='.Database::SYSTEM_COLLECTION_PROJECTS,
|
||||
],
|
||||
]);
|
||||
$projects = $this->getConsoleDB()->find('projects', [], $limit);
|
||||
Authorization::reset();
|
||||
|
||||
$projectIds = array_map (function ($project) {
|
||||
|
@ -294,7 +293,13 @@ class DeletesV1 extends Worker
|
|||
Console::info("Found {$count} projects " . ($executionEnd - $executionStart) . " seconds");
|
||||
}
|
||||
|
||||
protected function deleteByGroup(array $filters, Database $database, callable $callback = null)
|
||||
/**
|
||||
* @param string $collection collectionID
|
||||
* @param Query[] $queries
|
||||
* @param Database $database
|
||||
* @param callable $callback
|
||||
*/
|
||||
protected function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null)
|
||||
{
|
||||
$count = 0;
|
||||
$chunk = 0;
|
||||
|
@ -303,19 +308,13 @@ class DeletesV1 extends Worker
|
|||
$sum = $limit;
|
||||
|
||||
$executionStart = \microtime(true);
|
||||
|
||||
|
||||
while($sum === $limit) {
|
||||
$chunk++;
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$results = $database->getCollection([
|
||||
'limit' => $limit,
|
||||
'orderField' => '$id',
|
||||
'orderType' => 'ASC',
|
||||
'orderCast' => 'string',
|
||||
'filters' => $filters,
|
||||
]);
|
||||
$results = $database->find($collection, $queries, $limit, 0);
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
|
@ -334,6 +333,10 @@ class DeletesV1 extends Worker
|
|||
Console::info("Deleted {$count} document by group in " . ($executionEnd - $executionStart) . " seconds");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document certificates document
|
||||
* @return Database
|
||||
*/
|
||||
protected function deleteCertificates(Document $document)
|
||||
{
|
||||
$domain = $document->getAttribute('domain');
|
||||
|
@ -348,56 +351,48 @@ class DeletesV1 extends Worker
|
|||
Console::info("No certificate files found for {$domain}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $projectId
|
||||
* @return Database
|
||||
*/
|
||||
protected function getInternalDB($projectId): Database
|
||||
{
|
||||
global $register;
|
||||
|
||||
$cache = new Cache(new RedisCache($register->get('cache')));
|
||||
$dbForInternal = new Database(new MariaDB($register->get('db')), $cache);
|
||||
$dbForInternal->setNamespace('project_'.$projectId.'_internal'); // Main DB
|
||||
|
||||
return $dbForInternal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Database;
|
||||
* @param string $projectId
|
||||
* @return Database
|
||||
*/
|
||||
protected function getExternalDB($projectId): Database
|
||||
{
|
||||
global $register;
|
||||
|
||||
$cache = new Cache(new RedisCache($register->get('cache')));
|
||||
$dbForExternal = new Database(new MariaDB($register->get('db')), $cache);
|
||||
$dbForExternal->setNamespace('project_'.$projectId.'_external'); // Main DB
|
||||
|
||||
return $dbForExternal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Database
|
||||
*/
|
||||
protected function getConsoleDB(): Database
|
||||
{
|
||||
global $register;
|
||||
|
||||
$db = $register->get('db');
|
||||
$cache = $register->get('cache');
|
||||
|
||||
if($this->consoleDB === null) {
|
||||
$this->consoleDB = new Database();
|
||||
$this->consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));;
|
||||
$this->consoleDB->setNamespace('app_console'); // Main DB
|
||||
$this->consoleDB->setMocks(Config::getParam('collections', []));
|
||||
}
|
||||
|
||||
return $this->consoleDB;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Database;
|
||||
*/
|
||||
protected function getProjectDB($projectId): Database
|
||||
{
|
||||
global $register;
|
||||
|
||||
$db = $register->get('db');
|
||||
$cache = $register->get('cache');
|
||||
|
||||
$projectDB = new Database();
|
||||
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
|
||||
$projectDB->setNamespace('app_'.$projectId); // Main DB
|
||||
$projectDB->setMocks(Config::getParam('collections', []));
|
||||
|
||||
return $projectDB;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Database2
|
||||
*/
|
||||
protected function getInternalDB($projectId): Database2
|
||||
{
|
||||
global $register;
|
||||
|
||||
$cache = new Cache(new RedisCache($register->get('cache')));
|
||||
$dbForInternal = new Database2(new MariaDB($register->get('db')), $cache);
|
||||
$dbForInternal->setNamespace('project_'.$projectId.'_internal'); // Main DB
|
||||
$dbForConsole = new Database(new MariaDB($register->get('db')), $cache);
|
||||
$dbForConsole->setNamespace('project_console_internal'); // Main DB
|
||||
|
||||
return $dbForInternal;
|
||||
return $dbForConsole;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -465,10 +465,6 @@ class FunctionsV1 extends Worker
|
|||
|
||||
Authorization::reset();
|
||||
|
||||
if (false === $function) {
|
||||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
|
||||
$executionModel = new Execution();
|
||||
$executionUpdate = new Event('v1-webhooks', 'WebhooksV1');
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
||||
use Appwrite\Database\Adapter\Redis as RedisAdapter;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Cron\CronExpression;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Redis;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
require_once __DIR__.'/../workers.php';
|
||||
|
||||
|
@ -33,10 +33,20 @@ class TasksV1 extends Worker
|
|||
$db = $register->get('db');
|
||||
$cache = $register->get('cache');
|
||||
|
||||
$consoleDB = new Database();
|
||||
$consoleDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache));
|
||||
$consoleDB->setNamespace('app_console'); // Main DB
|
||||
$consoleDB->setMocks(Config::getParam('collections', []));
|
||||
$projectId = $this->args['projectId'] ?? null;
|
||||
$taskId = $this->args['$id'] ?? null;
|
||||
$updated = $this->args['updated'] ?? null;
|
||||
$next = $this->args['next'] ?? null;
|
||||
$delay = \time() - $next;
|
||||
$errors = [];
|
||||
$timeout = 60 * 5; // 5 minutes
|
||||
$errorLimit = 5;
|
||||
$logLimit = 5;
|
||||
$alert = '';
|
||||
|
||||
$cache = new Cache(new Redis($cache));
|
||||
$dbForConsole = new Database(new MariaDB($db), $cache);
|
||||
$dbForConsole->setNamespace('project_console_internal');
|
||||
|
||||
/*
|
||||
* 1. Get Original Task
|
||||
|
@ -51,30 +61,25 @@ class TasksV1 extends Worker
|
|||
* If error count bigger than allowed change status to pause
|
||||
*/
|
||||
|
||||
$taskId = $this->args['$id'] ?? null;
|
||||
$updated = $this->args['updated'] ?? null;
|
||||
$next = $this->args['next'] ?? null;
|
||||
$delay = \time() - $next;
|
||||
$errors = [];
|
||||
$timeout = 60 * 5; // 5 minutes
|
||||
$errorLimit = 5;
|
||||
$logLimit = 5;
|
||||
$alert = '';
|
||||
|
||||
if (empty($taskId)) {
|
||||
throw new Exception('Missing task $id');
|
||||
}
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$task = $consoleDB->getDocument($taskId);
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
if (\is_null($task->getId()) || Database::SYSTEM_COLLECTION_TASKS !== $task->getCollection()) {
|
||||
// Find the task in the $project->getAttribute('tasks') array
|
||||
$taskIndex = array_search($taskId, array_column($project->getAttributes()['tasks'], '$id'));
|
||||
|
||||
if ($taskIndex === false) {
|
||||
throw new Exception('Task Not Found');
|
||||
}
|
||||
|
||||
$task = $project->getAttribute('tasks')[$taskIndex];
|
||||
|
||||
if ($task->getAttribute('updated') !== $updated) { // Task have already been rescheduled by owner
|
||||
return;
|
||||
}
|
||||
|
@ -193,9 +198,11 @@ class TasksV1 extends Worker
|
|||
->setAttribute('delay', $delay)
|
||||
;
|
||||
|
||||
Authorization::disable();
|
||||
$project->findAndReplace('$id', $task->getId(), $task);
|
||||
|
||||
if (false === $consoleDB->updateDocument($task->getArrayCopy())) {
|
||||
Authorization::disable();
|
||||
|
||||
if (false === $dbForConsole->updateDocument('projects', $project->getId(), $project)) {
|
||||
throw new Exception('Failed saving tasks to DB');
|
||||
}
|
||||
|
||||
|
|
10
bin/worker-database
Normal file
10
bin/worker-database
Normal file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
|
||||
then
|
||||
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
|
||||
else
|
||||
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
|
||||
fi
|
||||
|
||||
QUEUE='v1-database' APP_INCLUDE='/usr/src/code/app/workers/database.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
|
16
composer.lock
generated
16
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "68ed82b309f6a9dd878ef031424ac00a",
|
||||
"content-hash": "ca8cf356c884e8d332b04bebf9d3b11b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
@ -115,16 +115,16 @@
|
|||
},
|
||||
{
|
||||
"name": "appwrite/php-runtimes",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/php-runtimes.git",
|
||||
"reference": "39be003cdff22c8447de151921001eb5d3bf2319"
|
||||
"reference": "cc7090a67d8824c779190b38873f0f8154f906b2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/php-runtimes/zipball/39be003cdff22c8447de151921001eb5d3bf2319",
|
||||
"reference": "39be003cdff22c8447de151921001eb5d3bf2319",
|
||||
"url": "https://api.github.com/repos/appwrite/php-runtimes/zipball/cc7090a67d8824c779190b38873f0f8154f906b2",
|
||||
"reference": "cc7090a67d8824c779190b38873f0f8154f906b2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -144,7 +144,7 @@
|
|||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3"
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
|
@ -164,9 +164,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/php-runtimes/issues",
|
||||
"source": "https://github.com/appwrite/php-runtimes/tree/0.3.0"
|
||||
"source": "https://github.com/appwrite/php-runtimes/tree/0.4.0"
|
||||
},
|
||||
"time": "2021-06-15T07:52:43+00:00"
|
||||
"time": "2021-06-23T07:17:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "chillerlan/php-qrcode",
|
||||
|
|
|
@ -240,6 +240,31 @@ services:
|
|||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
|
||||
appwrite-worker-database:
|
||||
entrypoint: worker-database
|
||||
container_name: appwrite-worker-database
|
||||
build:
|
||||
context: .
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
|
||||
appwrite-worker-certificates:
|
||||
entrypoint: worker-certificates
|
||||
container_name: appwrite-worker-certificates
|
||||
|
|
|
@ -7,6 +7,9 @@ use Resque;
|
|||
class Event
|
||||
{
|
||||
|
||||
const DATABASE_QUEUE_NAME= 'v1-database';
|
||||
const DATABASE_CLASS_NAME = 'DatabaseV1';
|
||||
|
||||
const DELETE_QUEUE_NAME = 'v1-deletes';
|
||||
const DELETE_CLASS_NAME = 'DeletesV1';
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use Appwrite\Utopia\Response\Filter;
|
|||
use Appwrite\Utopia\Response\Model;
|
||||
use Appwrite\Utopia\Response\Model\None;
|
||||
use Appwrite\Utopia\Response\Model\Any;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
use Appwrite\Utopia\Response\Model\BaseList;
|
||||
use Appwrite\Utopia\Response\Model\Collection;
|
||||
use Appwrite\Utopia\Response\Model\Continent;
|
||||
|
@ -22,6 +23,7 @@ use Appwrite\Utopia\Response\Model\ErrorDev;
|
|||
use Appwrite\Utopia\Response\Model\Execution;
|
||||
use Appwrite\Utopia\Response\Model\File;
|
||||
use Appwrite\Utopia\Response\Model\Func;
|
||||
use Appwrite\Utopia\Response\Model\Index;
|
||||
use Appwrite\Utopia\Response\Model\JWT;
|
||||
use Appwrite\Utopia\Response\Model\Key;
|
||||
use Appwrite\Utopia\Response\Model\Language;
|
||||
|
@ -63,6 +65,10 @@ class Response extends SwooleResponse
|
|||
// Database
|
||||
const MODEL_COLLECTION = 'collection';
|
||||
const MODEL_COLLECTION_LIST = 'collectionList';
|
||||
const MODEL_ATTRIBUTE = 'attribute';
|
||||
const MODEL_ATTRIBUTE_LIST = 'attributeList';
|
||||
const MODEL_INDEX = 'index';
|
||||
const MODEL_INDEX_LIST = 'indexList';
|
||||
const MODEL_RULE = 'rule';
|
||||
const MODEL_DOCUMENT = 'document';
|
||||
const MODEL_DOCUMENT_LIST = 'documentList';
|
||||
|
@ -150,6 +156,8 @@ class Response extends SwooleResponse
|
|||
->setModel(new ErrorDev())
|
||||
// Lists
|
||||
->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION))
|
||||
->setModel(new BaseList('Attributes List', self::MODEL_ATTRIBUTE_LIST, 'attributes', self::MODEL_ATTRIBUTE))
|
||||
->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX))
|
||||
->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
|
||||
->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER))
|
||||
->setModel(new BaseList('Sessions List', self::MODEL_SESSION_LIST, 'sessions', self::MODEL_SESSION))
|
||||
|
@ -174,6 +182,8 @@ class Response extends SwooleResponse
|
|||
// Entities
|
||||
->setModel(new Permissions())
|
||||
->setModel(new Collection())
|
||||
->setModel(new Attribute())
|
||||
->setModel(new Index())
|
||||
->setModel(new ModelDocument())
|
||||
->setModel(new Rule())
|
||||
->setModel(new Log())
|
||||
|
|
87
src/Appwrite/Utopia/Response/Model/Attribute.php
Normal file
87
src/Appwrite/Utopia/Response/Model/Attribute.php
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class Attribute extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$collection', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Collection ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16d55',
|
||||
])
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute ID.',
|
||||
'default' => '',
|
||||
'example' => '60ccf71b98a2d',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute type.',
|
||||
'default' => '',
|
||||
'example' => 'string',
|
||||
])
|
||||
->addRule('size', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute size.',
|
||||
'default' => 0,
|
||||
'example' => 128,
|
||||
])
|
||||
->addRule('required', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Is attribute required?',
|
||||
'default' => false,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('signed', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Is attribute signed?',
|
||||
'default' => true,
|
||||
'example' => true,
|
||||
'required' => false,
|
||||
])
|
||||
->addRule('array', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Is attribute an array?',
|
||||
'default' => false,
|
||||
'example' => false,
|
||||
'required' => false
|
||||
])
|
||||
->addRule('filters', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute filters.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true,
|
||||
'required' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'Attribute';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Collection
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_ATTRIBUTE;
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace Appwrite\Utopia\Response\Model;
|
|||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use stdClass;
|
||||
|
||||
class Collection extends Model
|
||||
{
|
||||
|
@ -16,36 +17,53 @@ class Collection extends Model
|
|||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('$permissions', [
|
||||
'type' => Response::MODEL_PERMISSIONS,
|
||||
'description' => 'Collection permissions.',
|
||||
'default' => new \stdClass,
|
||||
'example' => new \stdClass,
|
||||
'array' => false,
|
||||
->addRule('$read', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Collection read permissions.',
|
||||
'default' => '',
|
||||
'example' => 'role:all',
|
||||
'array' => true
|
||||
])
|
||||
->addRule('$write', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Collection write permissions.',
|
||||
'default' => '',
|
||||
'example' => 'user:608f9da25e7e1',
|
||||
'array' => true
|
||||
])
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Collection name.',
|
||||
'default' => '',
|
||||
'example' => 'Movies',
|
||||
'example' => '',
|
||||
])
|
||||
->addRule('dateCreated', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Collection creation date in Unix timestamp.',
|
||||
'default' => 0,
|
||||
'example' => 1592981250,
|
||||
])
|
||||
->addRule('dateUpdated', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Collection creation date in Unix timestamp.',
|
||||
'default' => 0,
|
||||
'example' => 1592981550,
|
||||
])
|
||||
->addRule('rules', [
|
||||
'type' => Response::MODEL_RULE,
|
||||
'description' => 'Collection rules.',
|
||||
->addRule('attributes', [
|
||||
'type' => Response::MODEL_ATTRIBUTE,
|
||||
'description' => 'Collection attributes.',
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('indexes', [
|
||||
'type' => Response::MODEL_INDEX,
|
||||
'description' => 'Collection indexes.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('attributesInQueue', [
|
||||
'type' => Response::MODEL_ATTRIBUTE,
|
||||
'description' => 'Collection attributes in creation queue.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
->addRule('indexesInQueue', [
|
||||
'type' => Response::MODEL_INDEX,
|
||||
'description' => 'Collection indexes in creation queue.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
@ -69,4 +87,4 @@ class Collection extends Model
|
|||
{
|
||||
return Response::MODEL_COLLECTION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,12 +41,20 @@ class Document extends Any
|
|||
'default' => '',
|
||||
'example' => '5e5ea5c15117e',
|
||||
])
|
||||
->addRule('$permissions', [
|
||||
'type' => Response::MODEL_PERMISSIONS,
|
||||
'description' => 'Document permissions.',
|
||||
'default' => new \stdClass,
|
||||
'example' => new \stdClass,
|
||||
'array' => false,
|
||||
]);
|
||||
->addRule('$read', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Document read permissions.',
|
||||
'default' => '',
|
||||
'example' => 'role:all',
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('$write', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Document write permissions.',
|
||||
'default' => '',
|
||||
'example' => 'user:608f9da25e7e1',
|
||||
'array' => true,
|
||||
])
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
76
src/Appwrite/Utopia/Response/Model/Index.php
Normal file
76
src/Appwrite/Utopia/Response/Model/Index.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class Index extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$collection', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Collection ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16d55',
|
||||
])
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Index ID.',
|
||||
'default' => '',
|
||||
'example' => '',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Index type.',
|
||||
'default' => '',
|
||||
'example' => '',
|
||||
])
|
||||
->addRule('attributes', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Index attributes.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('lengths', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Index lengths.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true,
|
||||
'required' => false,
|
||||
])
|
||||
->addRule('orders', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Index orders.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true,
|
||||
'required' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'Index';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Collection
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_INDEX;
|
||||
}
|
||||
}
|
|
@ -21,6 +21,12 @@ class Task extends Model
|
|||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('projectId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Project ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Task name.',
|
||||
|
|
|
@ -69,6 +69,10 @@ trait ProjectCustom
|
|||
'teams.write',
|
||||
'collections.read',
|
||||
'collections.write',
|
||||
'attributes.read',
|
||||
'attributes.write',
|
||||
'indexes.read',
|
||||
'indexes.write',
|
||||
'documents.read',
|
||||
'documents.write',
|
||||
'files.read',
|
||||
|
@ -110,6 +114,10 @@ trait ProjectCustom
|
|||
'database.collections.create',
|
||||
'database.collections.update',
|
||||
'database.collections.delete',
|
||||
'database.attributes.create',
|
||||
'database.attributes.delete',
|
||||
'database.indexes.create',
|
||||
'database.indexes.delete',
|
||||
'database.documents.create',
|
||||
'database.documents.update',
|
||||
'database.documents.delete',
|
||||
|
|
|
@ -11,42 +11,6 @@ trait DatabaseBase
|
|||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$actors = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Actors',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:member', 'role:admin'],
|
||||
'rules' => [
|
||||
[
|
||||
'label' => 'First Name',
|
||||
'key' => 'firstName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
[
|
||||
'label' => 'Last Name',
|
||||
'key' => 'lastName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 201);
|
||||
$this->assertEquals($actors['body']['name'], 'Actors');
|
||||
$this->assertIsArray($actors['body']['$permissions']);
|
||||
$this->assertIsArray($actors['body']['$permissions']['read']);
|
||||
$this->assertIsArray($actors['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $actors['body']['$permissions']['read']);
|
||||
$this->assertCount(2, $actors['body']['$permissions']['write']);
|
||||
|
||||
$movies = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
@ -54,50 +18,142 @@ trait DatabaseBase
|
|||
]), [
|
||||
'name' => 'Movies',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:member', 'role:admin'],
|
||||
'rules' => [
|
||||
[
|
||||
'label' => 'Name',
|
||||
'key' => 'name',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
[
|
||||
'label' => 'Release Year',
|
||||
'key' => 'releaseYear',
|
||||
'type' => 'numeric',
|
||||
'default' => 0,
|
||||
'required' => false,
|
||||
'array' => false
|
||||
],
|
||||
[
|
||||
'label' => 'Actors',
|
||||
'key' => 'actors',
|
||||
'type' => 'document',
|
||||
'default' => [],
|
||||
'required' => false,
|
||||
'array' => true,
|
||||
'list' => [$actors['body']['$id']],
|
||||
],
|
||||
],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($movies['headers']['status-code'], 201);
|
||||
$this->assertEquals($movies['body']['name'], 'Movies');
|
||||
$this->assertIsArray($movies['body']['$permissions']);
|
||||
$this->assertIsArray($movies['body']['$permissions']['read']);
|
||||
$this->assertIsArray($movies['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $movies['body']['$permissions']['read']);
|
||||
$this->assertCount(2, $movies['body']['$permissions']['write']);
|
||||
|
||||
return array_merge(['moviesId' => $movies['body']['$id'], 'actorsId' => $actors['body']['$id']]);
|
||||
return ['moviesId' => $movies['body']['$id']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateCollection
|
||||
*/
|
||||
public function testCreateAttributes(array $data): array
|
||||
{
|
||||
$title = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/attributes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'id' => 'title',
|
||||
'type' => 'string',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$releaseYear = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/attributes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'id' => 'releaseYear',
|
||||
'type' => 'integer',
|
||||
'size' => 0,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$actors = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/attributes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'id' => 'actors',
|
||||
'type' => 'string',
|
||||
'size' => 256,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals($title['headers']['status-code'], 201);
|
||||
$this->assertEquals($title['body']['$collection'], $data['moviesId']);
|
||||
$this->assertEquals($title['body']['$id'], 'title');
|
||||
$this->assertEquals($title['body']['type'], 'string');
|
||||
$this->assertEquals($title['body']['size'], 256);
|
||||
$this->assertEquals($title['body']['required'], true);
|
||||
|
||||
$this->assertEquals($releaseYear['headers']['status-code'], 201);
|
||||
$this->assertEquals($releaseYear['body']['$collection'], $data['moviesId']);
|
||||
$this->assertEquals($releaseYear['body']['$id'], 'releaseYear');
|
||||
$this->assertEquals($releaseYear['body']['type'], 'integer');
|
||||
$this->assertEquals($releaseYear['body']['size'], 0);
|
||||
$this->assertEquals($releaseYear['body']['required'], true);
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 201);
|
||||
$this->assertEquals($actors['body']['$collection'], $data['moviesId']);
|
||||
$this->assertEquals($actors['body']['$id'], 'actors');
|
||||
$this->assertEquals($actors['body']['type'], 'string');
|
||||
$this->assertEquals($actors['body']['size'], 256);
|
||||
$this->assertEquals($actors['body']['required'], false);
|
||||
$this->assertEquals($actors['body']['array'], true);
|
||||
|
||||
// wait for database worker to create attributes
|
||||
sleep(10);
|
||||
|
||||
$movies = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), []);
|
||||
|
||||
$this->assertEquals($movies['body']['$id'], $title['body']['$collection']);
|
||||
$this->assertEquals($movies['body']['$id'], $releaseYear['body']['$collection']);
|
||||
$this->assertEquals($movies['body']['$id'], $actors['body']['$collection']);
|
||||
$this->assertIsArray($movies['body']['attributesInQueue']);
|
||||
$this->assertCount(0, $movies['body']['attributesInQueue']);
|
||||
$this->assertIsArray($movies['body']['attributes']);
|
||||
$this->assertCount(3, $movies['body']['attributes']);
|
||||
$this->assertEquals($movies['body']['attributes'][0]['$id'], $title['body']['$id']);
|
||||
$this->assertEquals($movies['body']['attributes'][1]['$id'], $releaseYear['body']['$id']);
|
||||
$this->assertEquals($movies['body']['attributes'][2]['$id'], $actors['body']['$id']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateAttributes
|
||||
*/
|
||||
public function testCreateIndexes(array $data): array
|
||||
{
|
||||
$titleIndex = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/indexes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'id' => 'titleIndex',
|
||||
'type' => 'fulltext',
|
||||
'attributes' => ['title'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($titleIndex['headers']['status-code'], 201);
|
||||
$this->assertEquals($titleIndex['body']['$collection'], $data['moviesId']);
|
||||
$this->assertEquals($titleIndex['body']['$id'], 'titleIndex');
|
||||
$this->assertEquals($titleIndex['body']['type'], 'fulltext');
|
||||
$this->assertCount(1, $titleIndex['body']['attributes']);
|
||||
$this->assertEquals($titleIndex['body']['attributes'][0], 'title');
|
||||
|
||||
// wait for database worker to create index
|
||||
sleep(5);
|
||||
|
||||
$movies = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), []);
|
||||
|
||||
$this->assertEquals($movies['body']['$id'], $titleIndex['body']['$collection']);
|
||||
$this->assertIsArray($movies['body']['indexes']);
|
||||
$this->assertCount(1, $movies['body']['indexes']);
|
||||
$this->assertEquals($movies['body']['indexes'][0]['$id'], $titleIndex['body']['$id']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateIndexes
|
||||
*/
|
||||
public function testCreateDocument(array $data):array
|
||||
{
|
||||
$document1 = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
|
@ -105,21 +161,11 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Captain America',
|
||||
'title' => 'Captain America',
|
||||
'releaseYear' => 1944,
|
||||
'actors' => [
|
||||
[
|
||||
'$collection' => $data['actorsId'],
|
||||
'$permissions' => ['read' => [], 'write' => []],
|
||||
'firstName' => 'Chris',
|
||||
'lastName' => 'Evans',
|
||||
],
|
||||
[
|
||||
'$collection' => $data['actorsId'],
|
||||
'$permissions' => ['read' => [], 'write' => []],
|
||||
'firstName' => 'Samuel',
|
||||
'lastName' => 'Jackson',
|
||||
],
|
||||
'Chris Evans',
|
||||
'Samuel Jackson',
|
||||
]
|
||||
],
|
||||
'read' => ['user:'.$this->getUser()['$id']],
|
||||
|
@ -131,27 +177,12 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Spider-Man: Far From Home',
|
||||
'title' => 'Spider-Man: Far From Home',
|
||||
'releaseYear' => 2019,
|
||||
'actors' => [
|
||||
[
|
||||
'$collection' => $data['actorsId'],
|
||||
'$permissions' => ['read' => [], 'write' => []],
|
||||
'firstName' => 'Tom',
|
||||
'lastName' => 'Holland',
|
||||
],
|
||||
[
|
||||
'$collection' => $data['actorsId'],
|
||||
'$permissions' => ['read' => [], 'write' => []],
|
||||
'firstName' => 'Zendaya',
|
||||
'lastName' => 'Maree Stoermer',
|
||||
],
|
||||
[
|
||||
'$collection' => $data['actorsId'],
|
||||
'$permissions' => ['read' => [], 'write' => []],
|
||||
'firstName' => 'Samuel',
|
||||
'lastName' => 'Jackson',
|
||||
],
|
||||
'Tom Holland',
|
||||
'Zendaya Maree Stoermer',
|
||||
'Samuel Jackson',
|
||||
]
|
||||
],
|
||||
'read' => ['user:'.$this->getUser()['$id']],
|
||||
|
@ -163,21 +194,11 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Spider-Man: Homecoming',
|
||||
'title' => 'Spider-Man: Homecoming',
|
||||
'releaseYear' => 2017,
|
||||
'actors' => [
|
||||
[
|
||||
'$collection' => $data['actorsId'],
|
||||
'$permissions' => ['read' => [], 'write' => []],
|
||||
'firstName' => 'Tom',
|
||||
'lastName' => 'Holland',
|
||||
],
|
||||
[
|
||||
'$collection' => $data['actorsId'],
|
||||
'$permissions' => ['read' => [], 'write' => []],
|
||||
'firstName' => 'Zendaya',
|
||||
'lastName' => 'Maree Stoermer',
|
||||
],
|
||||
'Tom Holland',
|
||||
'Zendaya Maree Stoermer',
|
||||
],
|
||||
],
|
||||
'read' => ['user:'.$this->getUser()['$id']],
|
||||
|
@ -197,46 +218,40 @@ trait DatabaseBase
|
|||
|
||||
$this->assertEquals($document1['headers']['status-code'], 201);
|
||||
$this->assertEquals($document1['body']['$collection'], $data['moviesId']);
|
||||
$this->assertEquals($document1['body']['name'], 'Captain America');
|
||||
$this->assertEquals($document1['body']['title'], 'Captain America');
|
||||
$this->assertEquals($document1['body']['releaseYear'], 1944);
|
||||
$this->assertIsArray($document1['body']['$permissions']);
|
||||
$this->assertIsArray($document1['body']['$permissions']['read']);
|
||||
$this->assertIsArray($document1['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document1['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document1['body']['$permissions']['write']);
|
||||
$this->assertIsArray($document1['body']['$read']);
|
||||
$this->assertIsArray($document1['body']['$write']);
|
||||
$this->assertCount(1, $document1['body']['$read']);
|
||||
$this->assertCount(1, $document1['body']['$write']);
|
||||
$this->assertCount(2, $document1['body']['actors']);
|
||||
$this->assertEquals($document1['body']['actors'][0], 'Chris Evans');
|
||||
$this->assertEquals($document1['body']['actors'][1], 'Samuel Jackson');
|
||||
|
||||
$this->assertEquals($document2['headers']['status-code'], 201);
|
||||
$this->assertEquals($document2['body']['$collection'], $data['moviesId']);
|
||||
$this->assertEquals($document2['body']['name'], 'Spider-Man: Far From Home');
|
||||
$this->assertEquals($document2['body']['title'], 'Spider-Man: Far From Home');
|
||||
$this->assertEquals($document2['body']['releaseYear'], 2019);
|
||||
$this->assertIsArray($document2['body']['$permissions']);
|
||||
$this->assertIsArray($document2['body']['$permissions']['read']);
|
||||
$this->assertIsArray($document2['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document2['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document2['body']['$permissions']['write']);
|
||||
$this->assertIsArray($document2['body']['$read']);
|
||||
$this->assertIsArray($document2['body']['$write']);
|
||||
$this->assertCount(1, $document2['body']['$read']);
|
||||
$this->assertCount(1, $document2['body']['$write']);
|
||||
$this->assertCount(3, $document2['body']['actors']);
|
||||
$this->assertEquals($document2['body']['actors'][0]['firstName'], 'Tom');
|
||||
$this->assertEquals($document2['body']['actors'][0]['lastName'], 'Holland');
|
||||
$this->assertEquals($document2['body']['actors'][1]['firstName'], 'Zendaya');
|
||||
$this->assertEquals($document2['body']['actors'][1]['lastName'], 'Maree Stoermer');
|
||||
$this->assertEquals($document2['body']['actors'][2]['firstName'], 'Samuel');
|
||||
$this->assertEquals($document2['body']['actors'][2]['lastName'], 'Jackson');
|
||||
$this->assertEquals($document2['body']['actors'][0], 'Tom Holland');
|
||||
$this->assertEquals($document2['body']['actors'][1], 'Zendaya Maree Stoermer');
|
||||
$this->assertEquals($document2['body']['actors'][2], 'Samuel Jackson');
|
||||
|
||||
$this->assertEquals($document3['headers']['status-code'], 201);
|
||||
$this->assertEquals($document3['body']['$collection'], $data['moviesId']);
|
||||
$this->assertEquals($document3['body']['name'], 'Spider-Man: Homecoming');
|
||||
$this->assertEquals($document3['body']['title'], 'Spider-Man: Homecoming');
|
||||
$this->assertEquals($document3['body']['releaseYear'], 2017);
|
||||
$this->assertIsArray($document3['body']['$permissions']);
|
||||
$this->assertIsArray($document3['body']['$permissions']['read']);
|
||||
$this->assertIsArray($document3['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document3['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document3['body']['$permissions']['write']);
|
||||
$this->assertIsArray($document3['body']['$read']);
|
||||
$this->assertIsArray($document3['body']['$write']);
|
||||
$this->assertCount(1, $document3['body']['$read']);
|
||||
$this->assertCount(1, $document3['body']['$write']);
|
||||
$this->assertCount(2, $document3['body']['actors']);
|
||||
$this->assertEquals($document3['body']['actors'][0]['firstName'], 'Tom');
|
||||
$this->assertEquals($document3['body']['actors'][0]['lastName'], 'Holland');
|
||||
$this->assertEquals($document3['body']['actors'][1]['firstName'], 'Zendaya');
|
||||
$this->assertEquals($document3['body']['actors'][1]['lastName'], 'Maree Stoermer');
|
||||
$this->assertEquals($document2['body']['actors'][0], 'Tom Holland');
|
||||
$this->assertEquals($document2['body']['actors'][1], 'Zendaya Maree Stoermer');
|
||||
|
||||
$this->assertEquals($document4['headers']['status-code'], 400);
|
||||
|
||||
|
@ -252,9 +267,8 @@ trait DatabaseBase
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'orderField' => 'releaseYear',
|
||||
'orderType' => 'ASC',
|
||||
'orderCast' => 'int',
|
||||
'orderAttributes' => ['releaseYear'],
|
||||
'orderTypes' => ['ASC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
|
||||
|
@ -266,9 +280,8 @@ trait DatabaseBase
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'orderField' => 'releaseYear',
|
||||
'orderType' => 'DESC',
|
||||
'orderCast' => 'int',
|
||||
'orderAttributes' => ['releaseYear'],
|
||||
'orderTypes' => ['DESC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(1944, $documents['body']['documents'][2]['releaseYear']);
|
||||
|
@ -289,9 +302,8 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'limit' => 1,
|
||||
'orderField' => 'releaseYear',
|
||||
'orderType' => 'ASC',
|
||||
'orderCast' => 'int',
|
||||
'orderAttributes' => ['releaseYear'],
|
||||
'orderTypes' => ['ASC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
|
||||
|
@ -303,9 +315,8 @@ trait DatabaseBase
|
|||
], $this->getHeaders()), [
|
||||
'limit' => 2,
|
||||
'offset' => 1,
|
||||
'orderField' => 'releaseYear',
|
||||
'orderType' => 'ASC',
|
||||
'orderCast' => 'int',
|
||||
'orderAttributes' => ['releaseYear'],
|
||||
'orderTypes' => ['ASC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(2017, $documents['body']['documents'][0]['releaseYear']);
|
||||
|
@ -324,7 +335,7 @@ trait DatabaseBase
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'search' => 'Captain America',
|
||||
'queries' => ['title.search("Captain America")'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
|
||||
|
@ -334,7 +345,7 @@ trait DatabaseBase
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'search' => 'Homecoming',
|
||||
'queries' => ['title.search("Homecoming")'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(2017, $documents['body']['documents'][0]['releaseYear']);
|
||||
|
@ -344,7 +355,7 @@ trait DatabaseBase
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'search' => 'spider',
|
||||
'queries' => ['title.search("spider")'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(2019, $documents['body']['documents'][0]['releaseYear']);
|
||||
|
@ -353,52 +364,53 @@ trait DatabaseBase
|
|||
|
||||
return [];
|
||||
}
|
||||
// TODO@kodumbeats test for empty searches and misformatted queries
|
||||
|
||||
/**
|
||||
* @depends testCreateDocument
|
||||
*/
|
||||
public function testListDocumentsFilters(array $data):array
|
||||
{
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'filters' => [
|
||||
'actors.firstName=Tom'
|
||||
],
|
||||
]);
|
||||
// public function testListDocumentsFilters(array $data):array
|
||||
// {
|
||||
// $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'filters' => [
|
||||
// 'actors.firstName=Tom'
|
||||
// ],
|
||||
// ]);
|
||||
|
||||
$this->assertCount(2, $documents['body']['documents']);
|
||||
$this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['name']);
|
||||
$this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['name']);
|
||||
// $this->assertCount(2, $documents['body']['documents']);
|
||||
// $this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['name']);
|
||||
// $this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['name']);
|
||||
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'filters' => [
|
||||
'releaseYear=1944'
|
||||
],
|
||||
]);
|
||||
// $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'filters' => [
|
||||
// 'releaseYear=1944'
|
||||
// ],
|
||||
// ]);
|
||||
|
||||
$this->assertCount(1, $documents['body']['documents']);
|
||||
$this->assertEquals('Captain America', $documents['body']['documents'][0]['name']);
|
||||
// $this->assertCount(1, $documents['body']['documents']);
|
||||
// $this->assertEquals('Captain America', $documents['body']['documents'][0]['name']);
|
||||
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'filters' => [
|
||||
'releaseYear!=1944'
|
||||
],
|
||||
]);
|
||||
// $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// ], $this->getHeaders()), [
|
||||
// 'filters' => [
|
||||
// 'releaseYear!=1944'
|
||||
// ],
|
||||
// ]);
|
||||
|
||||
$this->assertCount(2, $documents['body']['documents']);
|
||||
$this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['name']);
|
||||
$this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['name']);
|
||||
// $this->assertCount(2, $documents['body']['documents']);
|
||||
// $this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['name']);
|
||||
// $this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['name']);
|
||||
|
||||
return [];
|
||||
}
|
||||
// return [];
|
||||
// }
|
||||
|
||||
/**
|
||||
* @depends testCreateDocument
|
||||
|
@ -410,35 +422,34 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Thor: Ragnaroc',
|
||||
'title' => 'Thor: Ragnaroc',
|
||||
'releaseYear' => 2017,
|
||||
'actors' => [],
|
||||
],
|
||||
'read' => ['user:'.$this->getUser()['$id'], 'testx'],
|
||||
'write' => ['user:'.$this->getUser()['$id'], 'testy'],
|
||||
'read' => ['user:'.$this->getUser()['$id'], 'user:testx'],
|
||||
'write' => ['user:'.$this->getUser()['$id'], 'user:testy'],
|
||||
]);
|
||||
|
||||
$id = $document['body']['$id'];
|
||||
$collection = $document['body']['$collection'];
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 201);
|
||||
$this->assertEquals($document['body']['name'], 'Thor: Ragnaroc');
|
||||
$this->assertEquals($document['body']['title'], 'Thor: Ragnaroc');
|
||||
$this->assertEquals($document['body']['releaseYear'], 2017);
|
||||
$this->assertEquals($document['body']['$permissions']['read'][1], 'testx');
|
||||
$this->assertEquals($document['body']['$permissions']['write'][1], 'testy');
|
||||
$this->assertEquals($document['body']['$read'][1], 'user:testx');
|
||||
$this->assertEquals($document['body']['$write'][1], 'user:testy');
|
||||
|
||||
$document = $this->client->call(Client::METHOD_PATCH, '/database/collections/' . $collection . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Thor: Ragnarok'
|
||||
'title' => 'Thor: Ragnarok',
|
||||
],
|
||||
'read' => ['user:'.$this->getUser()['$id']],
|
||||
'write' => ['user:'.$this->getUser()['$id']],
|
||||
]);
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 200);
|
||||
$this->assertEquals($document['body']['name'], 'Thor: Ragnarok');
|
||||
$this->assertEquals($document['body']['title'], 'Thor: Ragnarok');
|
||||
$this->assertEquals($document['body']['releaseYear'], 2017);
|
||||
|
||||
$document = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collection . '/documents/' . $id, array_merge([
|
||||
|
@ -450,7 +461,7 @@ trait DatabaseBase
|
|||
$collection = $document['body']['$collection'];
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 200);
|
||||
$this->assertEquals($document['body']['name'], 'Thor: Ragnarok');
|
||||
$this->assertEquals($document['body']['title'], 'Thor: Ragnarok');
|
||||
$this->assertEquals($document['body']['releaseYear'], 2017);
|
||||
|
||||
return [];
|
||||
|
@ -466,8 +477,9 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Thor: Ragnarok',
|
||||
'title' => 'Thor: Ragnarok',
|
||||
'releaseYear' => 2017,
|
||||
'actors' => [],
|
||||
],
|
||||
'read' => ['user:'.$this->getUser()['$id']],
|
||||
'write' => ['user:'.$this->getUser()['$id']],
|
||||
|
@ -512,7 +524,7 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Captain America',
|
||||
'title' => 'Captain America',
|
||||
'releaseYear' => 1944,
|
||||
'actors' => [],
|
||||
],
|
||||
|
@ -522,24 +534,23 @@ trait DatabaseBase
|
|||
|
||||
$this->assertEquals($document['headers']['status-code'], 201);
|
||||
$this->assertEquals($document['body']['$collection'], $data['moviesId']);
|
||||
$this->assertEquals($document['body']['name'], 'Captain America');
|
||||
$this->assertEquals($document['body']['title'], 'Captain America');
|
||||
$this->assertEquals($document['body']['releaseYear'], 1944);
|
||||
$this->assertIsArray($document['body']['$permissions']);
|
||||
$this->assertIsArray($document['body']['$permissions']['read']);
|
||||
$this->assertIsArray($document['body']['$permissions']['write']);
|
||||
$this->assertIsArray($document['body']['$read']);
|
||||
$this->assertIsArray($document['body']['$write']);
|
||||
|
||||
if($this->getSide() == 'client') {
|
||||
$this->assertCount(1, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document['body']['$read']);
|
||||
$this->assertCount(1, $document['body']['$write']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$read']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$write']);
|
||||
}
|
||||
|
||||
if($this->getSide() == 'server') {
|
||||
$this->assertCount(0, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(0, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals([], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals([], $document['body']['$permissions']['write']);
|
||||
$this->assertCount(0, $document['body']['$read']);
|
||||
$this->assertCount(0, $document['body']['$write']);
|
||||
$this->assertEquals([], $document['body']['$read']);
|
||||
$this->assertEquals([], $document['body']['$write']);
|
||||
}
|
||||
|
||||
// Updated and Inherit Permissions
|
||||
|
@ -549,7 +560,7 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Captain America 2',
|
||||
'title' => 'Captain America 2',
|
||||
'releaseYear' => 1945,
|
||||
'actors' => [],
|
||||
],
|
||||
|
@ -557,21 +568,21 @@ trait DatabaseBase
|
|||
]);
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 200);
|
||||
$this->assertEquals($document['body']['name'], 'Captain America 2');
|
||||
$this->assertEquals($document['body']['title'], 'Captain America 2');
|
||||
$this->assertEquals($document['body']['releaseYear'], 1945);
|
||||
|
||||
if($this->getSide() == 'client') {
|
||||
$this->assertCount(1, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document['body']['$read']);
|
||||
$this->assertCount(1, $document['body']['$write']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$read']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$write']);
|
||||
}
|
||||
|
||||
if($this->getSide() == 'server') {
|
||||
$this->assertCount(1, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(0, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals([], $document['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document['body']['$read']);
|
||||
$this->assertCount(0, $document['body']['$write']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$read']);
|
||||
$this->assertEquals([], $document['body']['$write']);
|
||||
}
|
||||
|
||||
$document = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents/' . $id, array_merge([
|
||||
|
@ -580,21 +591,21 @@ trait DatabaseBase
|
|||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 200);
|
||||
$this->assertEquals($document['body']['name'], 'Captain America 2');
|
||||
$this->assertEquals($document['body']['title'], 'Captain America 2');
|
||||
$this->assertEquals($document['body']['releaseYear'], 1945);
|
||||
|
||||
if($this->getSide() == 'client') {
|
||||
$this->assertCount(1, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document['body']['$read']);
|
||||
$this->assertCount(1, $document['body']['$write']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$read']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$write']);
|
||||
}
|
||||
|
||||
if($this->getSide() == 'server') {
|
||||
$this->assertCount(1, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(0, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals([], $document['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document['body']['$read']);
|
||||
$this->assertCount(0, $document['body']['$write']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$read']);
|
||||
$this->assertEquals([], $document['body']['$write']);
|
||||
}
|
||||
|
||||
// Reset Permissions
|
||||
|
@ -604,7 +615,7 @@ trait DatabaseBase
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'Captain America 3',
|
||||
'title' => 'Captain America 3',
|
||||
'releaseYear' => 1946,
|
||||
'actors' => [],
|
||||
],
|
||||
|
@ -618,12 +629,12 @@ trait DatabaseBase
|
|||
|
||||
if($this->getSide() == 'server') {
|
||||
$this->assertEquals($document['headers']['status-code'], 200);
|
||||
$this->assertEquals($document['body']['name'], 'Captain America 3');
|
||||
$this->assertEquals($document['body']['title'], 'Captain America 3');
|
||||
$this->assertEquals($document['body']['releaseYear'], 1946);
|
||||
$this->assertCount(0, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(0, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals([], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals([], $document['body']['$permissions']['write']);
|
||||
$this->assertCount(0, $document['body']['$read']);
|
||||
$this->assertCount(0, $document['body']['$write']);
|
||||
$this->assertEquals([], $document['body']['$read']);
|
||||
$this->assertEquals([], $document['body']['$write']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
|
|
@ -27,34 +27,49 @@ class DatabaseCustomServerTest extends Scope
|
|||
]), [
|
||||
'name' => 'Actors',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:member', 'role:admin'],
|
||||
'rules' => [
|
||||
[
|
||||
'label' => 'First Name',
|
||||
'key' => 'firstName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
[
|
||||
'label' => 'Last Name',
|
||||
'key' => 'lastName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 201);
|
||||
$this->assertEquals($actors['body']['name'], 'Actors');
|
||||
$this->assertIsArray($actors['body']['$permissions']);
|
||||
$this->assertIsArray($actors['body']['$permissions']['read']);
|
||||
$this->assertIsArray($actors['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $actors['body']['$permissions']['read']);
|
||||
$this->assertCount(2, $actors['body']['$permissions']['write']);
|
||||
|
||||
$firstName = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actors['body']['$id'] . '/attributes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'id' => 'firstName',
|
||||
'type' => 'string',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$lastName = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actors['body']['$id'] . '/attributes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'id' => 'lastName',
|
||||
'type' => 'string',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
// wait for database worker to finish creating attributes
|
||||
sleep(5);
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $actors['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), []);
|
||||
|
||||
$this->assertEquals($collection['body']['$id'], $firstName['body']['$collection']);
|
||||
$this->assertEquals($collection['body']['$id'], $lastName['body']['$collection']);
|
||||
$this->assertIsArray($collection['body']['attributes']);
|
||||
$this->assertCount(2, $collection['body']['attributes']);
|
||||
$this->assertEquals($collection['body']['attributes'][0]['$id'], $firstName['body']['$id']);
|
||||
$this->assertEquals($collection['body']['attributes'][1]['$id'], $lastName['body']['$id']);
|
||||
|
||||
// Add Documents to the collection
|
||||
$document1 = $this->client->call(Client::METHOD_POST, '/database/collections/' . $actors['body']['$id'] . '/documents', array_merge([
|
||||
|
@ -80,24 +95,22 @@ class DatabaseCustomServerTest extends Scope
|
|||
'read' => ['user:'.$this->getUser()['$id']],
|
||||
'write' => ['user:'.$this->getUser()['$id']],
|
||||
]);
|
||||
|
||||
|
||||
$this->assertEquals($document1['headers']['status-code'], 201);
|
||||
$this->assertEquals($document1['body']['$collection'], $actors['body']['$id']);
|
||||
$this->assertIsArray($document1['body']['$permissions']);
|
||||
$this->assertIsArray($document1['body']['$permissions']['read']);
|
||||
$this->assertIsArray($document1['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document1['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document1['body']['$permissions']['write']);
|
||||
$this->assertIsArray($document1['body']['$read']);
|
||||
$this->assertIsArray($document1['body']['$write']);
|
||||
$this->assertCount(1, $document1['body']['$read']);
|
||||
$this->assertCount(1, $document1['body']['$write']);
|
||||
$this->assertEquals($document1['body']['firstName'], 'Tom');
|
||||
$this->assertEquals($document1['body']['lastName'], 'Holland');
|
||||
|
||||
$this->assertEquals($document2['headers']['status-code'], 201);
|
||||
$this->assertEquals($document2['body']['$collection'], $actors['body']['$id']);
|
||||
$this->assertIsArray($document2['body']['$permissions']);
|
||||
$this->assertIsArray($document2['body']['$permissions']['read']);
|
||||
$this->assertIsArray($document2['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $document2['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document2['body']['$permissions']['write']);
|
||||
$this->assertIsArray($document2['body']['$read']);
|
||||
$this->assertIsArray($document2['body']['$write']);
|
||||
$this->assertCount(1, $document2['body']['$read']);
|
||||
$this->assertCount(1, $document2['body']['$write']);
|
||||
$this->assertEquals($document2['body']['firstName'], 'Samuel');
|
||||
$this->assertEquals($document2['body']['lastName'], 'Jackson');
|
||||
|
||||
|
|
|
@ -20,24 +20,6 @@ trait WebhooksBase
|
|||
'name' => 'Actors',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'rules' => [
|
||||
[
|
||||
'label' => 'First Name',
|
||||
'key' => 'firstName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
[
|
||||
'label' => 'Last Name',
|
||||
'key' => 'lastName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 201);
|
||||
|
@ -55,12 +37,10 @@ trait WebhooksBase
|
|||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], 'Actors');
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertCount(1, $webhook['data']['$read']);
|
||||
$this->assertCount(1, $webhook['data']['$write']);
|
||||
$this->assertCount(2, $webhook['data']['rules']);
|
||||
|
||||
return array_merge(['actorsId' => $actors['body']['$id']]);
|
||||
}
|
||||
|
@ -68,6 +48,60 @@ trait WebhooksBase
|
|||
/**
|
||||
* @depends testCreateCollection
|
||||
*/
|
||||
public function testCreateAttributes(array $data): array
|
||||
{
|
||||
$firstName = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'id' => 'firstName',
|
||||
'type' => 'string',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$lastName = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'id' => 'lastName',
|
||||
'type' => 'string',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals($firstName['headers']['status-code'], 201);
|
||||
$this->assertEquals($firstName['body']['$collection'], $data['actorsId']);
|
||||
$this->assertEquals($firstName['body']['$id'], 'firstName');
|
||||
$this->assertEquals($lastName['headers']['status-code'], 201);
|
||||
$this->assertEquals($lastName['body']['$collection'], $data['actorsId']);
|
||||
$this->assertEquals($lastName['body']['$id'], 'lastName');
|
||||
|
||||
// wait for database worker to kick in
|
||||
sleep(10);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.attributes.create');
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['$id'], 'lastName');
|
||||
|
||||
// TODO@kodumbeats test webhook for removing attribute
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateAttributes
|
||||
*/
|
||||
public function testCreateDocument(array $data): array
|
||||
{
|
||||
$document = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/documents', array_merge([
|
||||
|
|
|
@ -15,7 +15,7 @@ class WebhooksCustomServerTest extends Scope
|
|||
use SideServer;
|
||||
|
||||
/**
|
||||
* @depends testCreateCollection
|
||||
* @depends testCreateAttributes
|
||||
*/
|
||||
public function testUpdateCollection($data): array
|
||||
{
|
||||
|
@ -28,26 +28,6 @@ class WebhooksCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Actors1',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'rules' => [
|
||||
[
|
||||
'label' => 'First Name',
|
||||
'key' => 'firstName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
[
|
||||
'label' => 'Last Name',
|
||||
'key' => 'lastName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 200);
|
||||
|
@ -65,16 +45,73 @@ class WebhooksCustomServerTest extends Scope
|
|||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], 'Actors1');
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']['read']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']['write']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['read']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['write']);
|
||||
$this->assertCount(2, $webhook['data']['rules']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertCount(1, $webhook['data']['$read']);
|
||||
$this->assertCount(1, $webhook['data']['$write']);
|
||||
|
||||
return array_merge(['actorsId' => $actors['body']['$id']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateAttributes
|
||||
*/
|
||||
public function testCreateDeleteIndexes($data): array
|
||||
{
|
||||
$index = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/indexes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'id' => 'fullname',
|
||||
'type' => 'text',
|
||||
'attributes' => ['lastName', 'firstName'],
|
||||
'orders' => ['ASC', 'ASC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($index['headers']['status-code'], 201);
|
||||
$this->assertEquals($index['body']['$collection'], $data['actorsId']);
|
||||
$this->assertEquals($index['body']['$id'], 'fullname');
|
||||
|
||||
// wait for database worker to create index
|
||||
sleep(5);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.indexes.create');
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
|
||||
// TODO@kodumbeats test for indexes.delete
|
||||
// Remove index
|
||||
// $index = $this->client->call(Client::METHOD_DELETE, '/database/collections/' . $data['actorsId'] . '/indexes/' . $index['body']['$id'], array_merge([
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||
// 'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
// ]));
|
||||
|
||||
// // wait for database worker to remove index
|
||||
// sleep(5);
|
||||
|
||||
// $webhook = $this->getLastRequest();
|
||||
|
||||
// // $this->assertEquals($webhook['method'], 'DELETE');
|
||||
// $this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
// $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
// $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'database.indexes.delete');
|
||||
// $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
|
||||
// $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
// $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
// $this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testDeleteCollection(): array
|
||||
{
|
||||
/**
|
||||
|
@ -88,24 +125,6 @@ class WebhooksCustomServerTest extends Scope
|
|||
'name' => 'Demo',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'rules' => [
|
||||
[
|
||||
'label' => 'First Name',
|
||||
'key' => 'firstName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
[
|
||||
'label' => 'Last Name',
|
||||
'key' => 'lastName',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'array' => false
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 201);
|
||||
|
@ -131,12 +150,10 @@ class WebhooksCustomServerTest extends Scope
|
|||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], 'Demo');
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']['read']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']['write']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['read']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['write']);
|
||||
$this->assertCount(2, $webhook['data']['rules']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertCount(1, $webhook['data']['$read']);
|
||||
$this->assertCount(1, $webhook['data']['$write']);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
@ -306,8 +323,8 @@ class WebhooksCustomServerTest extends Scope
|
|||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test',
|
||||
'env' => 'php-8.0',
|
||||
'runtime' => ['role:all'],
|
||||
'execute' => ['role:all'],
|
||||
'runtime' => 'php-8.0',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
|
|
Loading…
Reference in a new issue