mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 08:58:35 +00:00
Merge branch '1.7.x' into 'lazy-load-relationships'.
This commit is contained in:
commit
bc556c559f
30 changed files with 685 additions and 221 deletions
1
.github/workflows/tests.yml
vendored
1
.github/workflows/tests.yml
vendored
|
|
@ -156,6 +156,7 @@ jobs:
|
|||
Sites,
|
||||
Proxy,
|
||||
Storage,
|
||||
Tokens,
|
||||
Teams,
|
||||
Users,
|
||||
Webhooks,
|
||||
|
|
|
|||
|
|
@ -2461,8 +2461,19 @@ return [
|
|||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
'filters' => ['datetime'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('accessedAt'),
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['datetime'],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
|
|
@ -2472,7 +2483,13 @@ return [
|
|||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
|
||||
[
|
||||
'$id' => '_key_accessedAt',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['accessedAt'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Amazon',
|
||||
],
|
||||
'apple' => [
|
||||
'name' => 'Apple',
|
||||
|
|
@ -21,6 +22,7 @@ return [
|
|||
'form' => 'apple.phtml', // Preparation for adding ability to customized OAuth UI forms, currently handled hardcoded.
|
||||
'beta' => true,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Apple',
|
||||
],
|
||||
'auth0' => [
|
||||
'name' => 'Auth0',
|
||||
|
|
@ -31,6 +33,7 @@ return [
|
|||
'form' => 'auth0.phtml',
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Auth0',
|
||||
],
|
||||
'authentik' => [
|
||||
'name' => 'Authentik',
|
||||
|
|
@ -41,6 +44,7 @@ return [
|
|||
'form' => 'authentik.phtml',
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Authentik',
|
||||
],
|
||||
'autodesk' => [
|
||||
'name' => 'Autodesk',
|
||||
|
|
@ -51,6 +55,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Autodesk',
|
||||
],
|
||||
'bitbucket' => [
|
||||
'name' => 'BitBucket',
|
||||
|
|
@ -61,6 +66,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Bitbucket',
|
||||
],
|
||||
'bitly' => [
|
||||
'name' => 'Bitly',
|
||||
|
|
@ -70,7 +76,8 @@ return [
|
|||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Bitly',
|
||||
],
|
||||
'box' => [
|
||||
'name' => 'Box',
|
||||
|
|
@ -80,7 +87,8 @@ return [
|
|||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Box',
|
||||
],
|
||||
'dailymotion' => [
|
||||
'name' => 'Dailymotion',
|
||||
|
|
@ -90,7 +98,8 @@ return [
|
|||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Dailymotion',
|
||||
],
|
||||
'discord' => [
|
||||
'name' => 'Discord',
|
||||
|
|
@ -101,6 +110,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Discord',
|
||||
],
|
||||
'disqus' => [
|
||||
'name' => 'Disqus',
|
||||
|
|
@ -111,6 +121,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Disqus',
|
||||
],
|
||||
'dropbox' => [
|
||||
'name' => 'Dropbox',
|
||||
|
|
@ -121,6 +132,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Dropbox',
|
||||
],
|
||||
'etsy' => [
|
||||
'name' => 'Etsy',
|
||||
|
|
@ -131,6 +143,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Etsy',
|
||||
],
|
||||
'facebook' => [
|
||||
'name' => 'Facebook',
|
||||
|
|
@ -141,6 +154,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Facebook',
|
||||
],
|
||||
'figma' => [
|
||||
'name' => 'Figma',
|
||||
|
|
@ -151,6 +165,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Figma',
|
||||
],
|
||||
'github' => [
|
||||
'name' => 'GitHub',
|
||||
|
|
@ -161,6 +176,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Github',
|
||||
],
|
||||
'gitlab' => [
|
||||
'name' => 'GitLab',
|
||||
|
|
@ -171,6 +187,7 @@ return [
|
|||
'form' => 'gitlab.phtml',
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Gitlab',
|
||||
],
|
||||
'google' => [
|
||||
'name' => 'Google',
|
||||
|
|
@ -181,6 +198,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Google',
|
||||
],
|
||||
'linkedin' => [
|
||||
'name' => 'LinkedIn',
|
||||
|
|
@ -191,6 +209,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Linkedin',
|
||||
],
|
||||
'microsoft' => [
|
||||
'name' => 'Microsoft',
|
||||
|
|
@ -201,6 +220,7 @@ return [
|
|||
'form' => 'microsoft.phtml',
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Microsoft',
|
||||
],
|
||||
'notion' => [
|
||||
'name' => 'Notion',
|
||||
|
|
@ -211,6 +231,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Notion',
|
||||
],
|
||||
'oidc' => [
|
||||
'name' => 'OpenID Connect',
|
||||
|
|
@ -221,6 +242,7 @@ return [
|
|||
'form' => 'oidc.phtml',
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Oidc',
|
||||
],
|
||||
'okta' => [
|
||||
'name' => 'Okta',
|
||||
|
|
@ -231,6 +253,7 @@ return [
|
|||
'form' => 'okta.phtml',
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Okta',
|
||||
],
|
||||
'paypal' => [
|
||||
'name' => 'PayPal',
|
||||
|
|
@ -240,7 +263,8 @@ return [
|
|||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Paypal',
|
||||
],
|
||||
'paypalSandbox' => [
|
||||
'name' => 'PayPal Sandbox',
|
||||
|
|
@ -250,7 +274,8 @@ return [
|
|||
'sandbox' => true,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Paypal',
|
||||
],
|
||||
'podio' => [
|
||||
'name' => 'Podio',
|
||||
|
|
@ -261,6 +286,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Podio',
|
||||
],
|
||||
'salesforce' => [
|
||||
'name' => 'Salesforce',
|
||||
|
|
@ -271,6 +297,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Salesforce',
|
||||
],
|
||||
'slack' => [
|
||||
'name' => 'Slack',
|
||||
|
|
@ -281,6 +308,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Slack',
|
||||
],
|
||||
'spotify' => [
|
||||
'name' => 'Spotify',
|
||||
|
|
@ -291,6 +319,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Spotify',
|
||||
],
|
||||
'stripe' => [
|
||||
'name' => 'Stripe',
|
||||
|
|
@ -300,7 +329,8 @@ return [
|
|||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Stripe',
|
||||
],
|
||||
'tradeshift' => [
|
||||
'name' => 'Tradeshift',
|
||||
|
|
@ -311,6 +341,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Tradeshift',
|
||||
],
|
||||
'tradeshiftBox' => [
|
||||
'name' => 'Tradeshift Sandbox',
|
||||
|
|
@ -321,6 +352,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Tradeshift',
|
||||
],
|
||||
'twitch' => [
|
||||
'name' => 'Twitch',
|
||||
|
|
@ -331,6 +363,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Twitch',
|
||||
],
|
||||
'wordpress' => [
|
||||
'name' => 'WordPress',
|
||||
|
|
@ -340,7 +373,8 @@ return [
|
|||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Wordpress',
|
||||
],
|
||||
'yahoo' => [
|
||||
'name' => 'Yahoo',
|
||||
|
|
@ -351,6 +385,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Yahoo',
|
||||
],
|
||||
'yammer' => [
|
||||
'name' => 'Yammer',
|
||||
|
|
@ -361,6 +396,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Yammer',
|
||||
],
|
||||
'yandex' => [
|
||||
'name' => 'Yandex',
|
||||
|
|
@ -371,6 +407,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Yandex',
|
||||
],
|
||||
'zoho' => [
|
||||
'name' => 'Zoho',
|
||||
|
|
@ -381,6 +418,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Zoho',
|
||||
],
|
||||
'zoom' => [
|
||||
'name' => 'Zoom',
|
||||
|
|
@ -391,6 +429,7 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Zoom',
|
||||
],
|
||||
// 'instagram' => [
|
||||
// 'name' => 'Instagram',
|
||||
|
|
@ -399,6 +438,7 @@ return [
|
|||
// 'enabled' => false,
|
||||
// 'beta' => false,
|
||||
// 'mock' => false,
|
||||
// 'class' => 'Appwrite\\Auth\\OAuth2\\Instagram',
|
||||
// ],
|
||||
// 'twitter' => [
|
||||
// 'name' => 'twitter',
|
||||
|
|
@ -407,6 +447,7 @@ return [
|
|||
// 'enabled' => false,
|
||||
// 'beta' => false,
|
||||
// 'mock' => false,
|
||||
// 'class' => 'Appwrite\\Auth\\OAuth2\\Twitter',
|
||||
// ],
|
||||
|
||||
// Keep Last
|
||||
|
|
@ -419,5 +460,6 @@ return [
|
|||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => true,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Mock',
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -9483,34 +9483,45 @@
|
|||
"description": "Token creation date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"$permissions": {
|
||||
"type": "array",
|
||||
"description": "Token permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-example": [
|
||||
"read(\"any\")"
|
||||
]
|
||||
},
|
||||
"resourceId": {
|
||||
"type": "string",
|
||||
"description": "Resource ID.",
|
||||
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
|
||||
},
|
||||
"resourceInternalId": {
|
||||
"type": "string",
|
||||
"description": "File ID.",
|
||||
"x-example": "1:1"
|
||||
},
|
||||
"resourceType": {
|
||||
"type": "string",
|
||||
"description": "Resource type.",
|
||||
"x-example": "file"
|
||||
"x-example": "files"
|
||||
},
|
||||
"expire": {
|
||||
"type": "string",
|
||||
"description": "Token expiration date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"accessedAt": {
|
||||
"type": "string",
|
||||
"description": "Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"$id",
|
||||
"$createdAt",
|
||||
"$permissions",
|
||||
"resourceId",
|
||||
"resourceInternalId",
|
||||
"resourceType",
|
||||
"expire"
|
||||
"expire",
|
||||
"accessedAt"
|
||||
]
|
||||
},
|
||||
"team": {
|
||||
|
|
|
|||
|
|
@ -38045,34 +38045,45 @@
|
|||
"description": "Token creation date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"$permissions": {
|
||||
"type": "array",
|
||||
"description": "Token permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-example": [
|
||||
"read(\"any\")"
|
||||
]
|
||||
},
|
||||
"resourceId": {
|
||||
"type": "string",
|
||||
"description": "Resource ID.",
|
||||
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
|
||||
},
|
||||
"resourceInternalId": {
|
||||
"type": "string",
|
||||
"description": "File ID.",
|
||||
"x-example": "1:1"
|
||||
},
|
||||
"resourceType": {
|
||||
"type": "string",
|
||||
"description": "Resource type.",
|
||||
"x-example": "file"
|
||||
"x-example": "files"
|
||||
},
|
||||
"expire": {
|
||||
"type": "string",
|
||||
"description": "Token expiration date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"accessedAt": {
|
||||
"type": "string",
|
||||
"description": "Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"$id",
|
||||
"$createdAt",
|
||||
"$permissions",
|
||||
"resourceId",
|
||||
"resourceInternalId",
|
||||
"resourceType",
|
||||
"expire"
|
||||
"expire",
|
||||
"accessedAt"
|
||||
]
|
||||
},
|
||||
"team": {
|
||||
|
|
|
|||
|
|
@ -28004,34 +28004,45 @@
|
|||
"description": "Token creation date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"$permissions": {
|
||||
"type": "array",
|
||||
"description": "Token permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-example": [
|
||||
"read(\"any\")"
|
||||
]
|
||||
},
|
||||
"resourceId": {
|
||||
"type": "string",
|
||||
"description": "Resource ID.",
|
||||
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
|
||||
},
|
||||
"resourceInternalId": {
|
||||
"type": "string",
|
||||
"description": "File ID.",
|
||||
"x-example": "1:1"
|
||||
},
|
||||
"resourceType": {
|
||||
"type": "string",
|
||||
"description": "Resource type.",
|
||||
"x-example": "file"
|
||||
"x-example": "files"
|
||||
},
|
||||
"expire": {
|
||||
"type": "string",
|
||||
"description": "Token expiration date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"accessedAt": {
|
||||
"type": "string",
|
||||
"description": "Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"$id",
|
||||
"$createdAt",
|
||||
"$permissions",
|
||||
"resourceId",
|
||||
"resourceInternalId",
|
||||
"resourceType",
|
||||
"expire"
|
||||
"expire",
|
||||
"accessedAt"
|
||||
]
|
||||
},
|
||||
"team": {
|
||||
|
|
|
|||
|
|
@ -9586,34 +9586,45 @@
|
|||
"description": "Token creation date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"$permissions": {
|
||||
"type": "array",
|
||||
"description": "Token permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-example": [
|
||||
"read(\"any\")"
|
||||
]
|
||||
},
|
||||
"resourceId": {
|
||||
"type": "string",
|
||||
"description": "Resource ID.",
|
||||
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
|
||||
},
|
||||
"resourceInternalId": {
|
||||
"type": "string",
|
||||
"description": "File ID.",
|
||||
"x-example": "1:1"
|
||||
},
|
||||
"resourceType": {
|
||||
"type": "string",
|
||||
"description": "Resource type.",
|
||||
"x-example": "file"
|
||||
"x-example": "files"
|
||||
},
|
||||
"expire": {
|
||||
"type": "string",
|
||||
"description": "Token expiration date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"accessedAt": {
|
||||
"type": "string",
|
||||
"description": "Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"$id",
|
||||
"$createdAt",
|
||||
"$permissions",
|
||||
"resourceId",
|
||||
"resourceInternalId",
|
||||
"resourceType",
|
||||
"expire"
|
||||
"expire",
|
||||
"accessedAt"
|
||||
]
|
||||
},
|
||||
"team": {
|
||||
|
|
|
|||
|
|
@ -38290,34 +38290,45 @@
|
|||
"description": "Token creation date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"$permissions": {
|
||||
"type": "array",
|
||||
"description": "Token permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-example": [
|
||||
"read(\"any\")"
|
||||
]
|
||||
},
|
||||
"resourceId": {
|
||||
"type": "string",
|
||||
"description": "Resource ID.",
|
||||
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
|
||||
},
|
||||
"resourceInternalId": {
|
||||
"type": "string",
|
||||
"description": "File ID.",
|
||||
"x-example": "1:1"
|
||||
},
|
||||
"resourceType": {
|
||||
"type": "string",
|
||||
"description": "Resource type.",
|
||||
"x-example": "file"
|
||||
"x-example": "files"
|
||||
},
|
||||
"expire": {
|
||||
"type": "string",
|
||||
"description": "Token expiration date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"accessedAt": {
|
||||
"type": "string",
|
||||
"description": "Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"$id",
|
||||
"$createdAt",
|
||||
"$permissions",
|
||||
"resourceId",
|
||||
"resourceInternalId",
|
||||
"resourceType",
|
||||
"expire"
|
||||
"expire",
|
||||
"accessedAt"
|
||||
]
|
||||
},
|
||||
"team": {
|
||||
|
|
|
|||
|
|
@ -28318,34 +28318,45 @@
|
|||
"description": "Token creation date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"$permissions": {
|
||||
"type": "array",
|
||||
"description": "Token permissions. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-example": [
|
||||
"read(\"any\")"
|
||||
]
|
||||
},
|
||||
"resourceId": {
|
||||
"type": "string",
|
||||
"description": "Resource ID.",
|
||||
"x-example": "5e5ea5c168bb8:5e5ea5c168bb8"
|
||||
},
|
||||
"resourceInternalId": {
|
||||
"type": "string",
|
||||
"description": "File ID.",
|
||||
"x-example": "1:1"
|
||||
},
|
||||
"resourceType": {
|
||||
"type": "string",
|
||||
"description": "Resource type.",
|
||||
"x-example": "file"
|
||||
"x-example": "files"
|
||||
},
|
||||
"expire": {
|
||||
"type": "string",
|
||||
"description": "Token expiration date in ISO 8601 format.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
},
|
||||
"accessedAt": {
|
||||
"type": "string",
|
||||
"description": "Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours.",
|
||||
"x-example": "2020-10-15T06:38:00.000+00:00"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"$id",
|
||||
"$createdAt",
|
||||
"$permissions",
|
||||
"resourceId",
|
||||
"resourceInternalId",
|
||||
"resourceType",
|
||||
"expire"
|
||||
"expire",
|
||||
"accessedAt"
|
||||
]
|
||||
},
|
||||
"team": {
|
||||
|
|
|
|||
|
|
@ -1212,8 +1212,8 @@ App::get('/v1/account/sessions/oauth2/:provider')
|
|||
throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.');
|
||||
}
|
||||
|
||||
$className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider);
|
||||
|
||||
$oAuthProviders = Config::getParam('oAuthProviders');
|
||||
$className = $oAuthProviders[$provider]['class'];
|
||||
if (!\class_exists($className)) {
|
||||
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1133,8 +1133,9 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->inject('resourceToken')
|
||||
->inject('deviceForFiles')
|
||||
->action(function (string $bucketId, string $fileId, Request $request, Response $response, Database $dbForProject, string $mode, Device $deviceForFiles) {
|
||||
->action(function (string $bucketId, string $fileId, Request $request, Response $response, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
|
|
@ -1145,10 +1146,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (!$fileSecurity && !$valid && !$isToken) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
|
|
@ -1158,6 +1160,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
|
@ -1282,8 +1288,9 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
->inject('request')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->inject('resourceToken')
|
||||
->inject('deviceForFiles')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Request $request, Database $dbForProject, string $mode, Device $deviceForFiles) {
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Request $request, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) {
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
|
|
@ -1293,10 +1300,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (!$fileSecurity && !$valid && !$isToken) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
|
|
@ -1306,6 +1314,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return
|
|||
const APP_KEY_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_USER_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_PROJECT_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_RESOURCE_TOKEN_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_FILE_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_BUSTER = 4318;
|
||||
|
|
@ -257,3 +258,10 @@ const RESOURCE_TYPE_PROVIDERS = 'providers';
|
|||
const RESOURCE_TYPE_TOPICS = 'topics';
|
||||
const RESOURCE_TYPE_SUBSCRIBERS = 'subscribers';
|
||||
const RESOURCE_TYPE_MESSAGES = 'messages';
|
||||
|
||||
// Resource types for Tokens
|
||||
|
||||
const TOKENS_RESOURCE_TYPE_FILES = 'files';
|
||||
const TOKENS_RESOURCE_TYPE_SITES = 'sites';
|
||||
const TOKENS_RESOURCE_TYPE_FUNCTIONS = 'functions';
|
||||
const TOKENS_RESOURCE_TYPE_DATABASES = 'databases';
|
||||
|
|
|
|||
|
|
@ -929,7 +929,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
|
|||
return new Document([]);
|
||||
}
|
||||
|
||||
if ($token->getAttribute('resourceType') === 'file') {
|
||||
if ($token->getAttribute('resourceType') === TOKENS_RESOURCE_TYPE_FILES) {
|
||||
$internalIds = explode(':', $token->getAttribute('resourceInternalId'));
|
||||
$ids = explode(':', $token->getAttribute('resourceId'));
|
||||
|
||||
|
|
@ -937,6 +937,12 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
|
|||
return new Document([]);
|
||||
}
|
||||
|
||||
$accessedAt = $token->getAttribute('accessedAt', 0);
|
||||
if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), - APP_RESOURCE_TOKEN_ACCESS)) > $accessedAt) {
|
||||
$token->setAttribute('accessedAt', DatabaseDateTime::now());
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), $token));
|
||||
}
|
||||
|
||||
return new Document([
|
||||
'bucketId' => $ids[0],
|
||||
'fileId' => $ids[1],
|
||||
|
|
|
|||
208
composer.lock
generated
208
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": "3310705774e8be0baeb36d7783665c28",
|
||||
"content-hash": "51959289a3f882160f5a9eeb605d41d7",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
|
@ -1179,16 +1179,16 @@
|
|||
},
|
||||
{
|
||||
"name": "open-telemetry/context",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opentelemetry-php/context.git",
|
||||
"reference": "0cba875ea1953435f78aec7f1d75afa87bdbf7f3"
|
||||
"reference": "5f553042b951d3fedf47925852c380159dfca801"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/opentelemetry-php/context/zipball/0cba875ea1953435f78aec7f1d75afa87bdbf7f3",
|
||||
"reference": "0cba875ea1953435f78aec7f1d75afa87bdbf7f3",
|
||||
"url": "https://api.github.com/repos/opentelemetry-php/context/zipball/5f553042b951d3fedf47925852c380159dfca801",
|
||||
"reference": "5f553042b951d3fedf47925852c380159dfca801",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1234,7 +1234,7 @@
|
|||
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
|
||||
"source": "https://github.com/open-telemetry/opentelemetry-php"
|
||||
},
|
||||
"time": "2024-08-21T00:29:20+00:00"
|
||||
"time": "2025-05-02T01:57:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "open-telemetry/exporter-otlp",
|
||||
|
|
@ -1365,16 +1365,16 @@
|
|||
},
|
||||
{
|
||||
"name": "open-telemetry/sdk",
|
||||
"version": "1.2.4",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opentelemetry-php/sdk.git",
|
||||
"reference": "47fcb66ae5328c5a799195247b1dce551d85873e"
|
||||
"reference": "05d9ceb6773b5bddcf485af6d4a6f543bbeb980b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/47fcb66ae5328c5a799195247b1dce551d85873e",
|
||||
"reference": "47fcb66ae5328c5a799195247b1dce551d85873e",
|
||||
"url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/05d9ceb6773b5bddcf485af6d4a6f543bbeb980b",
|
||||
"reference": "05d9ceb6773b5bddcf485af6d4a6f543bbeb980b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1451,20 +1451,20 @@
|
|||
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
|
||||
"source": "https://github.com/open-telemetry/opentelemetry-php"
|
||||
},
|
||||
"time": "2025-04-15T07:02:07+00:00"
|
||||
"time": "2025-05-01T23:20:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "open-telemetry/sem-conv",
|
||||
"version": "1.30.0",
|
||||
"version": "1.32.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opentelemetry-php/sem-conv.git",
|
||||
"reference": "4178c9f390da8e4dbca9b181a9d1efd50cf7ee0a"
|
||||
"reference": "16585cc0dbc3032a318e274043454679430d2ebf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/4178c9f390da8e4dbca9b181a9d1efd50cf7ee0a",
|
||||
"reference": "4178c9f390da8e4dbca9b181a9d1efd50cf7ee0a",
|
||||
"url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/16585cc0dbc3032a318e274043454679430d2ebf",
|
||||
"reference": "16585cc0dbc3032a318e274043454679430d2ebf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1508,7 +1508,7 @@
|
|||
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
|
||||
"source": "https://github.com/open-telemetry/opentelemetry-php"
|
||||
},
|
||||
"time": "2025-02-06T00:21:48+00:00"
|
||||
"time": "2025-05-05T03:58:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
|
|
@ -2726,19 +2726,20 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.31.0",
|
||||
"version": "v1.32.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-iconv": "*",
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
|
|
@ -2786,7 +2787,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -2802,11 +2803,11 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
"time": "2024-12-23T08:48:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php82",
|
||||
"version": "v1.31.0",
|
||||
"version": "v1.32.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php82.git",
|
||||
|
|
@ -2862,7 +2863,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php82/tree/v1.31.0"
|
||||
"source": "https://github.com/symfony/polyfill-php82/tree/v1.32.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -3300,16 +3301,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/cache",
|
||||
"version": "0.13.0",
|
||||
"version": "0.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/cache.git",
|
||||
"reference": "dee01dec33a211644d60f6cfa56b1b8176d3fae3"
|
||||
"reference": "646038f1d470b759c129348be8fc14da3c00bbd9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/cache/zipball/dee01dec33a211644d60f6cfa56b1b8176d3fae3",
|
||||
"reference": "dee01dec33a211644d60f6cfa56b1b8176d3fae3",
|
||||
"url": "https://api.github.com/repos/utopia-php/cache/zipball/646038f1d470b759c129348be8fc14da3c00bbd9",
|
||||
"reference": "646038f1d470b759c129348be8fc14da3c00bbd9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -3317,7 +3318,6 @@
|
|||
"ext-memcached": "*",
|
||||
"ext-redis": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/pools": "0.8.*",
|
||||
"utopia-php/telemetry": "0.1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -3346,9 +3346,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/cache/issues",
|
||||
"source": "https://github.com/utopia-php/cache/tree/0.13.0"
|
||||
"source": "https://github.com/utopia-php/cache/tree/0.12.0"
|
||||
},
|
||||
"time": "2025-04-17T04:20:26+00:00"
|
||||
"time": "2025-02-25T09:09:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cli",
|
||||
|
|
@ -3498,17 +3498,23 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "dev-manage-wildcards",
|
||||
"version": "0.66.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database",
|
||||
"reference": "5a98f7d7f7bb2dc15658abb93fac09c5c06ec5ac"
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "67d2ab418efba31dc76b3564cf043e2b3f98d027"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/67d2ab418efba31dc76b3564cf043e2b3f98d027",
|
||||
"reference": "67d2ab418efba31dc76b3564cf043e2b3f98d027",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"ext-pdo": "*",
|
||||
"php": ">=8.1",
|
||||
"utopia-php/cache": "0.13.*",
|
||||
"utopia-php/cache": "0.12.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/pools": "0.8.*"
|
||||
},
|
||||
|
|
@ -3528,38 +3534,7 @@
|
|||
"Utopia\\Database\\": "src/Database"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\E2E\\": "tests/e2e",
|
||||
"Tests\\Unit\\": "tests/unit"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"docker compose build"
|
||||
],
|
||||
"start": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"docker compose up -d"
|
||||
],
|
||||
"test": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"docker compose exec tests vendor/bin/phpunit --configuration phpunit.xml"
|
||||
],
|
||||
"lint": [
|
||||
"php -d memory_limit=2G ./vendor/bin/pint --test"
|
||||
],
|
||||
"format": [
|
||||
"php -d memory_limit=2G ./vendor/bin/pint"
|
||||
],
|
||||
"check": [
|
||||
"./vendor/bin/phpstan analyse --level 7 src tests --memory-limit 2G"
|
||||
],
|
||||
"coverage": [
|
||||
"./vendor/bin/coverage-check ./tmp/clover.xml 90"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
|
|
@ -3571,7 +3546,11 @@
|
|||
"upf",
|
||||
"utopia"
|
||||
],
|
||||
"time": "2025-05-02T06:57:15+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.66.0"
|
||||
},
|
||||
"time": "2025-04-16T07:10:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
|
|
@ -4610,28 +4589,28 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
"version": "0.10.2",
|
||||
"version": "0.10.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "1f9823ebcb8fd098607de0074f18f48e28985012"
|
||||
"reference": "6be02650cc361764900ade8c129f309df263eb74"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/1f9823ebcb8fd098607de0074f18f48e28985012",
|
||||
"reference": "1f9823ebcb8fd098607de0074f18f48e28985012",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/6be02650cc361764900ade8c129f309df263eb74",
|
||||
"reference": "6be02650cc361764900ade8c129f309df263eb74",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"adhocore/jwt": "^1.1",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cache": "0.13.*",
|
||||
"utopia-php/cache": "0.12.*",
|
||||
"utopia-php/framework": "0.*.*",
|
||||
"utopia-php/system": "0.9.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*.*",
|
||||
"phpstan/phpstan": "1.*.*",
|
||||
"laravel/pint": "1.2.*",
|
||||
"phpstan/phpstan": "1.8.*",
|
||||
"phpunit/phpunit": "^9.4"
|
||||
},
|
||||
"type": "library",
|
||||
|
|
@ -4653,9 +4632,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.10.2"
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.10.1"
|
||||
},
|
||||
"time": "2025-04-17T04:35:25+00:00"
|
||||
"time": "2025-03-18T11:44:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/websocket",
|
||||
|
|
@ -6060,16 +6039,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.6.22",
|
||||
"version": "9.6.23",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c"
|
||||
"reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
|
||||
"reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95",
|
||||
"reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -6080,7 +6059,7 @@
|
|||
"ext-mbstring": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"myclabs/deep-copy": "^1.12.1",
|
||||
"myclabs/deep-copy": "^1.13.1",
|
||||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"php": ">=7.3",
|
||||
|
|
@ -6143,7 +6122,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -6154,12 +6133,20 @@
|
|||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/sebastianbergmann",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/sebastianbergmann",
|
||||
"type": "thanks_dev"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-05T13:48:26+00:00"
|
||||
"time": "2025-05-02T06:40:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
|
|
@ -7271,16 +7258,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v7.2.5",
|
||||
"version": "v7.2.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "e51498ea18570c062e7df29d05a7003585b19b88"
|
||||
"reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/e51498ea18570c062e7df29d05a7003585b19b88",
|
||||
"reference": "e51498ea18570c062e7df29d05a7003585b19b88",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/0e2e3f38c192e93e622e41ec37f4ca70cfedf218",
|
||||
"reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -7344,7 +7331,7 @@
|
|||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v7.2.5"
|
||||
"source": "https://github.com/symfony/console/tree/v7.2.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7360,7 +7347,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-12T08:11:12+00:00"
|
||||
"time": "2025-04-07T19:09:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
|
|
@ -7561,7 +7548,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.31.0",
|
||||
"version": "v1.32.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
|
|
@ -7620,7 +7607,7 @@
|
|||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7640,7 +7627,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.31.0",
|
||||
"version": "v1.32.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
|
|
@ -7698,7 +7685,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7718,7 +7705,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.31.0",
|
||||
"version": "v1.32.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
|
|
@ -7779,7 +7766,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7799,7 +7786,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.31.0",
|
||||
"version": "v1.32.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
|
|
@ -7855,7 +7842,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7936,16 +7923,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "446e0d146f991dde3e73f45f2c97a9faad773c82"
|
||||
"reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82",
|
||||
"reference": "446e0d146f991dde3e73f45f2c97a9faad773c82",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/a214fe7d62bd4df2a76447c67c6b26e1d5e74931",
|
||||
"reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -8003,7 +7990,7 @@
|
|||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/string/tree/v7.2.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8019,7 +8006,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-13T13:31:26+00:00"
|
||||
"time": "2025-04-20T20:18:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "textalk/websocket",
|
||||
|
|
@ -8249,18 +8236,9 @@
|
|||
"time": "2024-03-07T20:33:40+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
{
|
||||
"package": "utopia-php/database",
|
||||
"version": "dev-manage-wildcards",
|
||||
"alias": "0.66.0",
|
||||
"alias_normalized": "0.66.0.0"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"utopia-php/database": 20
|
||||
},
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ services:
|
|||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: appwrite/console:5.3.0-sites-rc.42
|
||||
image: appwrite/console:5.3.0-sites-rc.43
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
|
@ -951,7 +951,7 @@ services:
|
|||
hostname: exc1
|
||||
<<: *x-logging
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/executor:0.7.13
|
||||
image: openruntimes/executor:0.7.14
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use Appwrite\Platform\Modules\Functions;
|
|||
use Appwrite\Platform\Modules\Projects;
|
||||
use Appwrite\Platform\Modules\Proxy;
|
||||
use Appwrite\Platform\Modules\Sites;
|
||||
use Appwrite\Platform\Modules\Storage;
|
||||
use Appwrite\Platform\Modules\Tokens;
|
||||
use Utopia\Platform\Platform;
|
||||
|
||||
class Appwrite extends Platform
|
||||
|
|
@ -21,6 +21,6 @@ class Appwrite extends Platform
|
|||
$this->addModule(new Sites\Module());
|
||||
$this->addModule(new Console\Module());
|
||||
$this->addModule(new Proxy\Module());
|
||||
$this->addModule(new Storage\Module());
|
||||
$this->addModule(new Tokens\Module());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use Utopia\Database\Validator\UID;
|
|||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Storage\Device;
|
||||
use Utopia\Swoole\Request;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Create extends Action
|
||||
|
|
@ -56,6 +57,7 @@ class Create extends Action
|
|||
))
|
||||
->param('siteId', '', new UID(), 'Site ID.')
|
||||
->param('deploymentId', '', new UID(), 'Deployment ID.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
|
|
@ -69,6 +71,7 @@ class Create extends Action
|
|||
public function action(
|
||||
string $siteId,
|
||||
string $deploymentId,
|
||||
Request $request,
|
||||
Response $response,
|
||||
Document $project,
|
||||
Database $dbForProject,
|
||||
|
|
@ -127,6 +130,7 @@ class Create extends Action
|
|||
'status' => 'waiting',
|
||||
'buildPath' => '',
|
||||
'buildLogs' => '',
|
||||
'type' => $request->getHeader('x-sdk-language') === 'cli' ? 'cli' : 'manual'
|
||||
]));
|
||||
|
||||
$site = $site
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files;
|
||||
namespace Appwrite\Platform\Modules\Tokens\Http\Tokens\Buckets\Files;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Extend\Exception;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files;
|
||||
namespace Appwrite\Platform\Modules\Tokens\Http\Tokens\Buckets\Files;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Event;
|
||||
|
|
@ -98,7 +98,7 @@ class Create extends Action
|
|||
'secret' => Auth::tokenGenerator(128),
|
||||
'resourceId' => $bucketId . ':' . $fileId,
|
||||
'resourceInternalId' => $bucket->getInternalId() . ':' . $file->getInternalId(),
|
||||
'resourceType' => 'files',
|
||||
'resourceType' => TOKENS_RESOURCE_TYPE_FILES,
|
||||
'expire' => $expire,
|
||||
'$permissions' => $permissions
|
||||
]));
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files;
|
||||
namespace Appwrite\Platform\Modules\Tokens\Http\Tokens\Buckets\Files;
|
||||
|
||||
use Appwrite\Extend\Exception as ExtendException;
|
||||
use Appwrite\SDK\AuthType;
|
||||
|
|
@ -63,7 +63,7 @@ class XList extends Action
|
|||
['bucket' => $bucket, 'file' => $file] = $this->getFileAndBucket($dbForProject, $bucketId, $fileId);
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
$queries[] = Query::equal('resourceType', ["files"]);
|
||||
$queries[] = Query::equal('resourceType', [TOKENS_RESOURCE_TYPE_FILES]);
|
||||
$queries[] = Query::equal('resourceInternalId', [$bucket->getInternalId() . ':' . $file->getInternalId()]);
|
||||
// Get cursor document if there was a cursor query
|
||||
$cursor = \array_filter($queries, function ($query) {
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Http\Tokens;
|
||||
namespace Appwrite\Platform\Modules\Tokens\Http\Tokens;
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Http\Tokens;
|
||||
namespace Appwrite\Platform\Modules\Tokens\Http\Tokens;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Http\Tokens\JWT;
|
||||
namespace Appwrite\Platform\Modules\Tokens\Http\Tokens\JWT;
|
||||
|
||||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Extend\Exception;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Http\Tokens;
|
||||
namespace Appwrite\Platform\Modules\Tokens\Http\Tokens;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Event;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage;
|
||||
namespace Appwrite\Platform\Modules\Tokens;
|
||||
|
||||
use Appwrite\Platform\Modules\Storage\Services\Http;
|
||||
use Appwrite\Platform\Modules\Tokens\Services\Http;
|
||||
use Utopia\Platform;
|
||||
|
||||
class Module extends Platform\Module
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Services;
|
||||
namespace Appwrite\Platform\Modules\Tokens\Services;
|
||||
|
||||
use Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files\Create as CreateFileToken;
|
||||
use Appwrite\Platform\Modules\Storage\Http\Tokens\Buckets\Files\XList as ListFileTokens;
|
||||
use Appwrite\Platform\Modules\Storage\Http\Tokens\Delete as DeleteToken;
|
||||
use Appwrite\Platform\Modules\Storage\Http\Tokens\Get as GetToken;
|
||||
use Appwrite\Platform\Modules\Storage\Http\Tokens\JWT\Get as GetTokenJWT;
|
||||
use Appwrite\Platform\Modules\Storage\Http\Tokens\Update as UpdateToken;
|
||||
use Appwrite\Platform\Modules\Tokens\Http\Tokens\Buckets\Files\Create as CreateFileToken;
|
||||
use Appwrite\Platform\Modules\Tokens\Http\Tokens\Buckets\Files\XList as ListFileTokens;
|
||||
use Appwrite\Platform\Modules\Tokens\Http\Tokens\Delete as DeleteToken;
|
||||
use Appwrite\Platform\Modules\Tokens\Http\Tokens\Get as GetToken;
|
||||
use Appwrite\Platform\Modules\Tokens\Http\Tokens\JWT\Get as GetTokenJWT;
|
||||
use Appwrite\Platform\Modules\Tokens\Http\Tokens\Update as UpdateToken;
|
||||
use Utopia\Platform\Service;
|
||||
|
||||
class Http extends Service
|
||||
|
|
@ -22,23 +22,24 @@ class ResourceToken extends Model
|
|||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('$permissions', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Token permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).',
|
||||
'default' => '',
|
||||
'example' => ['read("any")'],
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('resourceId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Resource ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c168bb8:5e5ea5c168bb8',
|
||||
])
|
||||
->addRule('resourceInternalId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'File ID.',
|
||||
'default' => '',
|
||||
'example' => '1:1',
|
||||
])
|
||||
->addRule('resourceType', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Resource type.',
|
||||
'default' => '',
|
||||
'example' => 'file',
|
||||
'example' => TOKENS_RESOURCE_TYPE_FILES,
|
||||
])
|
||||
->addRule('expire', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
|
|
@ -46,6 +47,12 @@ class ResourceToken extends Model
|
|||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('accessedAt', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_RESOURCE_TOKEN_ACCESS / 60 / 60 . ' hours.',
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2005,7 +2005,14 @@ class SitesCustomServerTest extends Scope
|
|||
$this->assertEquals(200, $site['headers']['status-code']);
|
||||
$this->assertEquals('index.html', $site['body']['fallbackFile']);
|
||||
|
||||
$deployment = $this->createDuplicateDeployment($siteId, $deploymentId1);
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/sites/' . $siteId . '/deployments/duplicate', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-sdk-language' => 'cli'
|
||||
], $this->getHeaders()), [
|
||||
'deploymentId' => $deploymentId1,
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
$deploymentId2 = $deployment['body']['$id'];
|
||||
|
|
@ -2016,6 +2023,27 @@ class SitesCustomServerTest extends Scope
|
|||
$this->assertGreaterThan(0, $deployment['body']['sourceSize']);
|
||||
$this->assertEquals(0, $deployment['body']['buildSize']);
|
||||
$this->assertEquals($deployment['body']['sourceSize'], $deployment['body']['totalSize']);
|
||||
$this->assertEquals('cli', $deployment['body']['type']);
|
||||
|
||||
// create another duplicate deployment with manual trigger
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/sites/' . $siteId . '/deployments/duplicate', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'deploymentId' => $deploymentId1,
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
$deploymentId2 = $deployment['body']['$id'];
|
||||
$this->assertNotEmpty($deploymentId2);
|
||||
|
||||
$deployment = $this->getDeployment($siteId, $deploymentId2);
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertGreaterThan(0, $deployment['body']['sourceSize']);
|
||||
$this->assertEquals(0, $deployment['body']['buildSize']);
|
||||
$this->assertEquals($deployment['body']['sourceSize'], $deployment['body']['totalSize']);
|
||||
$this->assertEquals('manual', $deployment['body']['type']);
|
||||
|
||||
$this->assertEventually(function () use ($siteId, $deploymentId2) {
|
||||
$site = $this->getSite($siteId);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,287 @@
|
|||
|
||||
namespace Tests\E2E\Services\Tokens;
|
||||
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
|
||||
trait TokensBase
|
||||
{
|
||||
public function testCreateBucketAndFile(): array
|
||||
{
|
||||
$bucket = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/storage/buckets',
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],
|
||||
[
|
||||
'name' => 'Test Bucket',
|
||||
'bucketId' => ID::unique(),
|
||||
'allowedFileExtensions' => ['jpg', 'png', 'jfif'],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(201, $bucket['headers']['status-code']);
|
||||
$this->assertNotEmpty($bucket['body']['$id']);
|
||||
|
||||
$bucketId = $bucket['body']['$id'];
|
||||
|
||||
$file = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/storage/buckets/' . $bucketId . '/files',
|
||||
[
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],
|
||||
[
|
||||
'fileId' => ID::unique(),
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(201, $file['headers']['status-code']);
|
||||
$this->assertNotEmpty($file['body']['$id']);
|
||||
|
||||
$fileId = $file['body']['$id'];
|
||||
|
||||
$token = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/tokens/buckets/' . $bucketId . '/files/' . $fileId,
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(201, $token['headers']['status-code']);
|
||||
$this->assertEquals($bucketId . ':' . $fileId, $token['body']['resourceId']);
|
||||
$this->assertEquals(TOKENS_RESOURCE_TYPE_FILES, $token['body']['resourceType']);
|
||||
|
||||
return [
|
||||
'fileId' => $fileId,
|
||||
'bucketId' => $bucketId,
|
||||
'tokenId' => $token['body']['$id'],
|
||||
'guestHeaders' => [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateBucketAndFile
|
||||
*/
|
||||
public function testFailuresWithoutToken(array $data): array
|
||||
{
|
||||
$fileId = $data['fileId'];
|
||||
$bucketId = $data['bucketId'];
|
||||
$guestHeaders = $data['guestHeaders'];
|
||||
|
||||
// File preview. Should fail as an anonymous user with no form of any access to the file.
|
||||
$failedPreview = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview',
|
||||
$guestHeaders
|
||||
);
|
||||
$this->assertEquals(401, $failedPreview['body']['code']);
|
||||
$this->assertEquals(401, $failedPreview['headers']['status-code']);
|
||||
$this->assertEquals('user_unauthorized', $failedPreview['body']['type']);
|
||||
$this->assertEquals('The current user is not authorized to perform the requested action.', $failedPreview['body']['message']);
|
||||
|
||||
// Extended file preview. Should fail as an anonymous user with no form of any access to the file.
|
||||
$failedCustomPreview = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview',
|
||||
$guestHeaders,
|
||||
[
|
||||
'width' => 300,
|
||||
'height' => 100,
|
||||
'borderRadius' => '50',
|
||||
'opacity' => '0.5',
|
||||
'output' => 'png',
|
||||
'rotation' => '45'
|
||||
]
|
||||
);
|
||||
$this->assertEquals(401, $failedCustomPreview['body']['code']);
|
||||
$this->assertEquals(401, $failedCustomPreview['headers']['status-code']);
|
||||
$this->assertEquals('user_unauthorized', $failedCustomPreview['body']['type']);
|
||||
$this->assertEquals('The current user is not authorized to perform the requested action.', $failedCustomPreview['body']['message']);
|
||||
|
||||
// File view. Should fail as an anonymous user with no form of any access to the file.
|
||||
$failedView = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view',
|
||||
$guestHeaders
|
||||
);
|
||||
$this->assertEquals(401, $failedView['body']['code']);
|
||||
$this->assertEquals(401, $failedView['headers']['status-code']);
|
||||
$this->assertEquals('user_unauthorized', $failedView['body']['type']);
|
||||
$this->assertEquals('The current user is not authorized to perform the requested action.', $failedView['body']['message']);
|
||||
|
||||
// File download. Should fail as an anonymous user with no form of any access to the file.
|
||||
$failedDownload = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download',
|
||||
$guestHeaders
|
||||
);
|
||||
$this->assertEquals(401, $failedDownload['body']['code']);
|
||||
$this->assertEquals(401, $failedDownload['headers']['status-code']);
|
||||
$this->assertEquals('user_unauthorized', $failedDownload['body']['type']);
|
||||
$this->assertEquals('The current user is not authorized to perform the requested action.', $failedDownload['body']['message']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateBucketAndFile
|
||||
*/
|
||||
public function testPreviewFileWithToken(array $data): array
|
||||
{
|
||||
$fileId = $data['fileId'];
|
||||
$tokenId = $data['tokenId'];
|
||||
$bucketId = $data['bucketId'];
|
||||
$guestHeaders = $data['guestHeaders'];
|
||||
$adminHeaders = array_merge($guestHeaders, ['x-appwrite-key' => $this->getProject()['apiKey']]);
|
||||
|
||||
// Generate JWT as an admin user.
|
||||
$tokenJWT = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/tokens/' . $tokenId . '/jwt/',
|
||||
$adminHeaders
|
||||
);
|
||||
$this->assertEquals(200, $tokenJWT['headers']['status-code']);
|
||||
$this->assertArrayHasKey('jwt', $tokenJWT['body']);
|
||||
|
||||
$tokenJWT = $tokenJWT['body']['jwt'];
|
||||
|
||||
// Generate a preview
|
||||
$filePreview = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview',
|
||||
$guestHeaders,
|
||||
[
|
||||
'token' => $tokenJWT
|
||||
]
|
||||
);
|
||||
$this->assertEquals(200, $filePreview['headers']['status-code']);
|
||||
$this->assertEquals('image/png', $filePreview['headers']['content-type']);
|
||||
$this->assertNotEmpty($filePreview['body']);
|
||||
|
||||
$image = new \Imagick();
|
||||
$image->readImageBlob($filePreview['body']);
|
||||
$original = new \Imagick(__DIR__ . '/../../../resources/logo.png');
|
||||
|
||||
$this->assertEquals($image->getImageWidth(), $original->getImageWidth());
|
||||
$this->assertEquals($image->getImageHeight(), $original->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
|
||||
$data['jwtToken'] = $tokenJWT;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testPreviewFileWithToken
|
||||
*/
|
||||
public function testCustomPreviewFileWithToken(array $data): array
|
||||
{
|
||||
$fileId = $data['fileId'];
|
||||
$bucketId = $data['bucketId'];
|
||||
$jwtToken = $data['jwtToken'];
|
||||
$guestHeaders = $data['guestHeaders'];
|
||||
|
||||
// Generate an extended preview
|
||||
$customFilePreview = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview/',
|
||||
$guestHeaders,
|
||||
[
|
||||
'width' => 300,
|
||||
'height' => 100,
|
||||
'borderRadius' => '50',
|
||||
'opacity' => '0.5',
|
||||
'output' => 'png',
|
||||
'rotation' => '45',
|
||||
'token' => $jwtToken
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $customFilePreview['headers']['status-code']);
|
||||
$this->assertEquals('image/png', $customFilePreview['headers']['content-type']);
|
||||
$this->assertNotEmpty($customFilePreview['body']);
|
||||
|
||||
$image = new \Imagick();
|
||||
$image->readImageBlob($customFilePreview['body']);
|
||||
$original = new \Imagick(__DIR__ . '/../../../resources/logo-after.png');
|
||||
|
||||
$this->assertEquals($image->getImageWidth(), $original->getImageWidth());
|
||||
$this->assertEquals($image->getImageHeight(), $original->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testPreviewFileWithToken
|
||||
*/
|
||||
public function testViewFileWithToken(array $data): void
|
||||
{
|
||||
$fileId = $data['fileId'];
|
||||
$bucketId = $data['bucketId'];
|
||||
$jwtToken = $data['jwtToken'];
|
||||
$guestHeaders = $data['guestHeaders'];
|
||||
|
||||
$fileView = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view',
|
||||
$guestHeaders,
|
||||
[
|
||||
'token' => $jwtToken
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $fileView['headers']['status-code']);
|
||||
|
||||
$image = new \Imagick();
|
||||
$image->readImageBlob($fileView['body']);
|
||||
$original = new \Imagick(__DIR__ . '/../../../resources/logo.png');
|
||||
|
||||
$this->assertEquals($image->getImageWidth(), $original->getImageWidth());
|
||||
$this->assertEquals($image->getImageHeight(), $original->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testPreviewFileWithToken
|
||||
*/
|
||||
public function testDownloadFileWithToken(array $data): void
|
||||
{
|
||||
$fileId = $data['fileId'];
|
||||
$bucketId = $data['bucketId'];
|
||||
$jwtToken = $data['jwtToken'];
|
||||
$guestHeaders = $data['guestHeaders'];
|
||||
|
||||
$fileFailedDownload = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download',
|
||||
$guestHeaders,
|
||||
[
|
||||
'token' => $jwtToken
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $fileFailedDownload['headers']['status-code']);
|
||||
|
||||
$image = new \Imagick();
|
||||
$image->readImageBlob($fileFailedDownload['body']);
|
||||
$original = new \Imagick(__DIR__ . '/../../../resources/logo.png');
|
||||
|
||||
$this->assertEquals($image->getImageWidth(), $original->getImageWidth());
|
||||
$this->assertEquals($image->getImageHeight(), $original->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use Utopia\Database\DateTime;
|
|||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
|
||||
class TokensCustomServerTest extends Scope
|
||||
{
|
||||
|
|
@ -60,19 +61,19 @@ class TokensCustomServerTest extends Scope
|
|||
|
||||
$fileId = $file['body']['$id'];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
|
||||
$token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(201, $res['headers']['status-code']);
|
||||
$this->assertEquals('files', $res['body']['resourceType']);
|
||||
$this->assertEquals(201, $token['headers']['status-code']);
|
||||
$this->assertEquals('files', $token['body']['resourceType']);
|
||||
|
||||
$data = [];
|
||||
$data['fileId'] = $fileId;
|
||||
$data['bucketId'] = $bucketId;
|
||||
$data['tokenId'] = $res['body']['$id'];
|
||||
return $data;
|
||||
return [
|
||||
'fileId' => $fileId,
|
||||
'bucketId' => $bucketId,
|
||||
'tokenId' => $token['body']['$id'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -82,15 +83,28 @@ class TokensCustomServerTest extends Scope
|
|||
{
|
||||
$tokenId = $data['tokenId'];
|
||||
|
||||
$expiry = DateTime::now();
|
||||
$res = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, array_merge([
|
||||
// Finite expiry
|
||||
$expiry = DateTime::addSeconds(new \DateTime(), 3600);
|
||||
$token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'expire' => $expiry,
|
||||
]);
|
||||
|
||||
$this->assertEquals($expiry, $res['body']['expire']);
|
||||
$dateValidator = new DatetimeValidator();
|
||||
$this->assertTrue($dateValidator->isValid($token['body']['expire']));
|
||||
|
||||
// Infinite expiry
|
||||
$token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'expire' => null,
|
||||
]);
|
||||
|
||||
$this->assertEmpty($token['body']['expire']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue