mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
408
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da736631b2 | ||
|
|
9db6f9cb75 | ||
|
|
b06354b99a | ||
|
|
a797951bec | ||
|
|
bb0007a1e8 | ||
|
|
507717fdf7 | ||
|
|
057397197b | ||
|
|
c398d5fba9 | ||
|
|
4dc700927e | ||
|
|
4a148e6ef9 | ||
|
|
2ff0ae61c8 | ||
|
|
b06460b562 | ||
|
|
0bf8cead51 | ||
|
|
add1142d1f | ||
|
|
86896a6d3c | ||
|
|
4fd4af312d | ||
|
|
4b7a7496ff | ||
|
|
0c93e7d545 | ||
|
|
469d0859fc | ||
|
|
4a96d89ee6 | ||
|
|
2aa2b8df91 | ||
|
|
ef938a1c39 | ||
|
|
e342009c9e | ||
|
|
41d89f1b7a | ||
|
|
ad6aff6af2 | ||
|
|
9b52f6f8f6 | ||
|
|
68ae8ce348 | ||
|
|
87b0bfcdfe | ||
|
|
d37bab37e6 | ||
|
|
7810d54238 | ||
|
|
b3f9404b93 | ||
|
|
d4b5d7df73 | ||
|
|
e93f479157 | ||
|
|
a1b1f97162 | ||
|
|
4ce2426c3d | ||
|
|
25b3680b1d | ||
|
|
c910c98b32 | ||
|
|
c442dd3ef1 | ||
|
|
bf5aa7b86c | ||
|
|
b42cc11eba | ||
|
|
79573b1d47 | ||
|
|
55103a1d04 | ||
|
|
6e71a3ca4c | ||
|
|
1f173eb3c3 | ||
|
|
2db205d186 | ||
|
|
1d84f1666d | ||
|
|
aa6390062f | ||
|
|
455b9b3ca7 | ||
|
|
45ead583c6 | ||
|
|
750ccdf33d | ||
|
|
745e9e2bea | ||
|
|
230148c06e | ||
|
|
3197ebb655 | ||
|
|
af3a0bb34b | ||
|
|
ea1099b112 | ||
|
|
f9542e2be2 | ||
|
|
3e291492fb | ||
|
|
e7dc7a6fba | ||
|
|
b525605d1b | ||
|
|
dc968a1fa4 | ||
|
|
ebee3536f5 | ||
|
|
8c8073d7aa | ||
|
|
d284c29e2a | ||
|
|
0fae37a999 | ||
|
|
fce4f72ca9 | ||
|
|
77968be454 | ||
|
|
4f905e06e2 | ||
|
|
ed39fd7999 | ||
|
|
71cd882324 | ||
|
|
68d7ff9c55 | ||
|
|
8ca083ed27 | ||
|
|
600da2a504 | ||
|
|
6bd52875dc | ||
|
|
88dffcffbf | ||
|
|
07214de370 | ||
|
|
d56bd44f67 | ||
|
|
a39970c59a | ||
|
|
b30890c1d6 | ||
|
|
5c1f6244c8 | ||
|
|
7156036120 | ||
|
|
627adb43e0 | ||
|
|
9ad08694ed | ||
|
|
baa7a170d9 | ||
|
|
60726757ab | ||
|
|
7b55a9810f | ||
|
|
d995dbb159 | ||
|
|
1180dc0781 | ||
|
|
2951a1b7b8 | ||
|
|
a7dbb3daea | ||
|
|
33000134df | ||
|
|
b893599ba8 | ||
|
|
8f87b9cb5e | ||
|
|
b303bd1051 | ||
|
|
60a4266204 | ||
|
|
637bf4f231 | ||
|
|
2a260c3d5f | ||
|
|
b8321d3bb0 | ||
|
|
66610cfd4e | ||
|
|
149fa141d0 | ||
|
|
9305c86367 | ||
|
|
0e6d3279d7 | ||
|
|
c0cb4681ae | ||
|
|
b9fb10a379 | ||
|
|
b39a118bba | ||
|
|
9f2ff0e1f7 | ||
|
|
15cabd018d | ||
|
|
8a5a6037b1 | ||
|
|
dde6968e50 | ||
|
|
71349385b4 | ||
|
|
6f299e922c | ||
|
|
7047ffe3dd | ||
|
|
73e3f2869f | ||
|
|
e4f63ed0c9 | ||
|
|
720dfb97e8 | ||
|
|
f18aa6b648 | ||
|
|
b760a88af7 | ||
|
|
74bcfe1e08 | ||
|
|
2afba50a8c | ||
|
|
15b12551a0 | ||
|
|
22f44c51d6 | ||
|
|
128dc34a52 | ||
|
|
ecc3f61f1e | ||
|
|
61f4c7957a | ||
|
|
ffb2a02ea0 | ||
|
|
f6135a0e04 | ||
|
|
f13c029751 | ||
|
|
d8bde641e9 | ||
|
|
3733df6fc5 | ||
|
|
b5d26bb426 | ||
|
|
fa4529846c | ||
|
|
1fc790802d | ||
|
|
52ababa800 | ||
|
|
b3c1dea8d7 | ||
|
|
f51c387cd8 | ||
|
|
3dd1c3de13 | ||
|
|
4472437696 | ||
|
|
ca39c2cde5 | ||
|
|
a7b74cede8 | ||
|
|
24bfad100d | ||
|
|
a8de338d5f | ||
|
|
9c0772f125 | ||
|
|
d90e2621a1 | ||
|
|
572870e320 | ||
|
|
046d1190cf | ||
|
|
a6af0cc73a | ||
|
|
f12481ce20 | ||
|
|
a280a565f6 | ||
|
|
c80b40cec7 | ||
|
|
5ebb7e23a9 | ||
|
|
6f188a03d5 | ||
|
|
7318ebf1d8 | ||
|
|
e222221ec9 | ||
|
|
fdf5367e39 | ||
|
|
42c75c43de | ||
|
|
28a6f6de00 | ||
|
|
c03b56c0de | ||
|
|
e21f53f4c7 | ||
|
|
462a2d505d | ||
|
|
654125a6a8 | ||
|
|
d4e5a1bdf2 | ||
|
|
26e07b8c26 | ||
|
|
2a4f191a69 | ||
|
|
aec26277c7 | ||
|
|
887820dbec | ||
|
|
18371eb511 | ||
|
|
c38d319aeb | ||
|
|
9c55da5b99 | ||
|
|
3019551db5 | ||
|
|
d787408e1d | ||
|
|
c86702430b | ||
|
|
597dc308a6 | ||
|
|
f89dc6c1ae | ||
|
|
95902fa897 | ||
|
|
d2aa971ed3 | ||
|
|
9a1b5d4eee | ||
|
|
a5486128d4 | ||
|
|
14b1cc6e48 | ||
|
|
f9257c1ec9 | ||
|
|
45e938b4ba | ||
|
|
c177d54f59 | ||
|
|
de7f69ae3f | ||
|
|
7249083152 | ||
|
|
e00a73f442 | ||
|
|
d5bd6a0475 | ||
|
|
c2d4997810 | ||
|
|
c9d83cb3f5 | ||
|
|
de03506c0a | ||
|
|
b6349b17f2 | ||
|
|
2e699ef8b9 | ||
|
|
f5034a6ad8 | ||
|
|
929baa17db | ||
|
|
8ded7c5942 | ||
|
|
9c30f32281 | ||
|
|
94c309d61e | ||
|
|
dfe87a0d37 | ||
|
|
bb77319703 | ||
|
|
dc7bb627d5 | ||
|
|
2652a21332 | ||
|
|
f35b80ba1a | ||
|
|
6cc5d1595d | ||
|
|
5073a86581 | ||
|
|
4619e03d64 | ||
|
|
d48ef373a7 | ||
|
|
4cb20b3fe3 | ||
|
|
f1c68af091 | ||
|
|
803244ccf7 | ||
|
|
215d55a997 | ||
|
|
16a2dd0b27 | ||
|
|
ab1e510348 | ||
|
|
232f1b1c05 | ||
|
|
1606141a5a | ||
|
|
c8f8b6ff0c | ||
|
|
095ee8511b | ||
|
|
bb0889fdba | ||
|
|
8154a8524a | ||
|
|
0e567e3e68 | ||
|
|
f150cffa17 | ||
|
|
f4efb81832 | ||
|
|
ddde13a78f | ||
|
|
a643cde26d | ||
|
|
5f3316ff18 | ||
|
|
9be7f4d72c | ||
|
|
76f4483dda | ||
|
|
fb4e3e1b9d | ||
|
|
e2d3624713 | ||
|
|
55a33c135c | ||
|
|
411951f9d5 | ||
|
|
caa699e181 | ||
|
|
d9773f44b1 | ||
|
|
46dd8fdc68 | ||
|
|
94d02aff4f | ||
|
|
d23f993a6c | ||
|
|
bfe639fb70 | ||
|
|
568651291e | ||
|
|
09075a05db | ||
|
|
9f80952251 | ||
|
|
d0e0f67fee | ||
|
|
f16de4abb9 | ||
|
|
7bbe08f23e | ||
|
|
3229956eef | ||
|
|
254f026458 | ||
|
|
248d3aea7a | ||
|
|
11042af051 | ||
|
|
07d55d17a3 | ||
|
|
abfab60eec | ||
|
|
fc3ac122dd | ||
|
|
3963b632d8 | ||
|
|
1936a01464 | ||
|
|
2cbfa6930f | ||
|
|
33a856af41 | ||
|
|
5d1d937fde | ||
|
|
83ec855f4b | ||
|
|
5ce9b8eaeb | ||
|
|
be983eb68a | ||
|
|
c6f144313d | ||
|
|
ae8ec1c736 | ||
|
|
19d7f02371 | ||
|
|
f0660f3fda | ||
|
|
9ded176cf2 | ||
|
|
2e10cd0009 | ||
|
|
7ff664e62b | ||
|
|
9dd1939d1f | ||
|
|
8dfdfcb522 | ||
|
|
b63c2804f1 | ||
|
|
ced2270571 | ||
|
|
d3436077a1 | ||
|
|
e06349e803 | ||
|
|
9849b9d678 | ||
|
|
22136867ed | ||
|
|
2df621f9c5 | ||
|
|
9a599e2015 | ||
|
|
431dd96b98 | ||
|
|
4d8f950955 | ||
|
|
08e559180d | ||
|
|
4cb63068de | ||
|
|
f062b39cfa | ||
|
|
635d77350a | ||
|
|
9f07a2bca4 | ||
|
|
06ee421965 | ||
|
|
c3c69cc43b | ||
|
|
e47d53ddcc | ||
|
|
290a7b27db | ||
|
|
bad74bd0b8 | ||
|
|
5e5b22d649 | ||
|
|
1b17c32405 | ||
|
|
d56dff954f | ||
|
|
c525e15ea5 | ||
|
|
0c64eaf441 | ||
|
|
248e538518 | ||
|
|
1a07123abe | ||
|
|
35578bfada | ||
|
|
cc6f5fea6d | ||
|
|
bd772c97cf | ||
|
|
12e3af6ad7 | ||
|
|
f0b6eeb303 | ||
|
|
b40769b086 | ||
|
|
16821a28fc | ||
|
|
5572c4a375 | ||
|
|
2494c9afb3 | ||
|
|
223523f722 | ||
|
|
61d9db8c67 | ||
|
|
4970aa7426 | ||
|
|
5e8951fbe0 | ||
|
|
c8993d7f71 | ||
|
|
97c5705447 | ||
|
|
5d5c1d8f43 | ||
|
|
a0afce666f | ||
|
|
4540362f42 | ||
|
|
3065f53d83 | ||
|
|
74f181d7a8 | ||
|
|
337eda8538 | ||
|
|
20c3641ac1 | ||
|
|
33f7056e7a | ||
|
|
73e7c98131 | ||
|
|
1157d6fd10 | ||
|
|
536cff9cc6 | ||
|
|
62014fda26 | ||
|
|
fea3544d4b | ||
|
|
679de3574f | ||
|
|
cfd82d9709 | ||
|
|
21245836c7 | ||
|
|
b5ca4c1166 | ||
|
|
780799f87a | ||
|
|
4579e41ace | ||
|
|
19cf94bd7e | ||
|
|
981a1278e2 | ||
|
|
13b98409ae | ||
|
|
518389d32c | ||
|
|
800db0b99d | ||
|
|
cfa4530797 | ||
|
|
d42841d80a | ||
|
|
3b668f7806 | ||
|
|
32b290a231 | ||
|
|
365aaca56d | ||
|
|
1c726d0466 | ||
|
|
c903caabcc | ||
|
|
53a117bd0f | ||
|
|
72f5793928 | ||
|
|
b8e3a19586 | ||
|
|
e36de6b72b | ||
|
|
bcec5c0922 | ||
|
|
72186f1882 | ||
|
|
e4d70a4d4f | ||
|
|
6d19d76bac | ||
|
|
55bebd92f3 | ||
|
|
0d4df67958 | ||
|
|
356fbed325 | ||
|
|
4578819a58 | ||
|
|
6099313cb4 | ||
|
|
487663f892 | ||
|
|
d8e769ef1f | ||
|
|
41dbe1a384 | ||
|
|
631c00023e | ||
|
|
4478edc211 | ||
|
|
2be8895dfd | ||
|
|
1722e9e416 | ||
|
|
57a46b98ec | ||
|
|
74c0f6a140 | ||
|
|
892cfe01b2 | ||
|
|
bf1af094c1 | ||
|
|
2f5dc7782f | ||
|
|
c70915306d | ||
|
|
b5c5f76acc | ||
|
|
6f861a91ee | ||
|
|
0483c7efb5 | ||
|
|
fb29fe7b3c | ||
|
|
1bf1766822 | ||
|
|
57edb4a385 | ||
|
|
17c555ab6c | ||
|
|
d6bd72cfd3 | ||
|
|
8c9123beaa | ||
|
|
3d967e695f | ||
|
|
a7d7e39dfd | ||
|
|
38cb95e940 | ||
|
|
b2b20c48b3 | ||
|
|
fed6579491 | ||
|
|
8cb85cafbd | ||
|
|
55e560bb41 | ||
|
|
dd9a40221e | ||
|
|
24300cd3bd | ||
|
|
4d5961c3ab | ||
|
|
afb40218d7 | ||
|
|
3daa3821ef | ||
|
|
84cec0e32c | ||
|
|
7bae15d4fe | ||
|
|
0180f72067 | ||
|
|
f537091eb2 | ||
|
|
c99c83a006 | ||
|
|
113828cd00 | ||
|
|
477add3022 | ||
|
|
8aa5714173 | ||
|
|
fdb83c51f7 | ||
|
|
c15739bba7 | ||
|
|
1ce84f1650 | ||
|
|
f618a8b563 | ||
|
|
9346efc24a | ||
|
|
a5e57a9a67 | ||
|
|
cc724218b0 | ||
|
|
706ce4b3b6 | ||
|
|
c08355df8d | ||
|
|
2d5904e3d0 | ||
|
|
d1318cf016 | ||
|
|
91921859a2 | ||
|
|
a058925252 | ||
|
|
fadb24f295 | ||
|
|
748119334d | ||
|
|
cb05b87dda | ||
|
|
aa36d944db |
Generated
+217
-403
File diff suppressed because it is too large
Load Diff
@@ -8,68 +8,41 @@ on:
|
||||
|
||||
permissions: read-all
|
||||
|
||||
# Add stricter error-detection patterns so issue text doesn't trigger agent error detection.
|
||||
# After merging this file run `gh aw compile` to regenerate the lock file.
|
||||
env:
|
||||
GH_AW_ERROR_PATTERNS: >-
|
||||
[
|
||||
{"id":"gh-action-error","pattern":"^::(error)(?:\\\\s+[^:]*)?::(.+)","level_group":1,"message_group":2,"description":"GitHub Actions workflow command - error"},
|
||||
{"id":"gh-action-warning","pattern":"^::(warning)(?:\\\\s+[^:]*)?::(.+)","level_group":1,"message_group":2,"description":"GitHub Actions workflow command - warning"},
|
||||
{"id":"bracketed-level","pattern":"^\\[(ERROR|CRITICAL|WARNING|WARN)\\]\\s+(.+)","level_group":1,"message_group":2,"description":"Bracketed log level at start of line"},
|
||||
{"id":"timestamped-copilot","pattern":"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z\\s+\\[(ERROR|WARN|WARNING|CRITICAL)\\]\\s+(.+)","level_group":1,"message_group":3,"description":"Timestamped Copilot CLI messages"}
|
||||
]
|
||||
|
||||
network: defaults
|
||||
|
||||
safe-outputs:
|
||||
add-labels:
|
||||
max: 100
|
||||
target: "*"
|
||||
max: 5
|
||||
add-comment:
|
||||
max: 10
|
||||
target: "*"
|
||||
|
||||
tools:
|
||||
web-fetch:
|
||||
web-search:
|
||||
github:
|
||||
toolsets:
|
||||
- default
|
||||
- labels
|
||||
|
||||
timeout-minutes: 10
|
||||
timeout_minutes: 10
|
||||
source: githubnext/agentics/workflows/issue-triage.md@0837fb7b24c3b84ee77fb7c8cfa8735c48be347a
|
||||
---
|
||||
# Agentic Triage
|
||||
|
||||
<!-- Note - this file can be customized to your needs. Replace this section directly, or add further instructions here. After editing run 'gh aw compile' -->
|
||||
|
||||
You're a triage assistant for GitHub issues. Your task is to analyze issues that were either created in the last 24 hours or updated (with a new comment) in the last 24 hours, and perform initial triage tasks for each of them.
|
||||
You're a triage assistant for GitHub issues. Your task is to analyze issues created in the last 24 hours and perform initial triage tasks for each of them.
|
||||
|
||||
1. First, use the `list_issues` tool to retrieve all issues created or updated in the last 24 hours. The `since` parameter filters by the issue's `updated_at` timestamp, which includes both newly created issues and recently commented issues. Calculate the timestamp from 24 hours ago (example: 2025-11-06T20:27:14Z for reference) and use it for the `since` parameter.
|
||||
1. First, use the `list_issues` tool to retrieve all issues created in the last 24 hours. Filter issues by using the `since` parameter with a timestamp from 24 hours ago (calculate: current time minus 24 hours in ISO 8601 format).
|
||||
|
||||
2. For each issue found, perform the following triage tasks:
|
||||
|
||||
3. Use the `get_comments` tool to retrieve all the comments on the issue.
|
||||
3. Select appropriate labels for the issue from the provided list.
|
||||
|
||||
4. Check for spam and quality issue descriptions and comments first:
|
||||
|
||||
- **Non-English Content**: If the issue is primarily written in a non-English language, add a respectful and appreciative comment explaining that while you appreciate their contribution, the majority of the community communicates in English and kindly ask them to repost in English so everyone can follow along and help. Provide a friendly translation of your message in their language if possible.
|
||||
- **Multiple Topics**: If the issue discusses multiple unrelated topics or problems, add a comment explaining that each issue should focus on one clear topic so the team can effectively solve the right problem. Politely ask them to split it into separate issues.
|
||||
- **Obvious Spam or Bot-Generated Content**: If the issue/comment is obviously spam, generated by a bot, or something that is not an actual issue to be worked on, add an issue comment with a one-sentence analysis and move to the next issue.
|
||||
4. Retrieve the issue content using the `get_issue` tool. If the issue is obviously spam, or generated by bot, or something else that is not an actual issue to be worked on, then add an issue comment to the issue with a one sentence analysis and move to the next issue.
|
||||
|
||||
5. Retrieve the issue content using the `get_issue` tool for any issues that pass the spam checks.
|
||||
5. Next, use the GitHub tools to gather additional context about the issue:
|
||||
|
||||
6. Next, use the GitHub tools to gather additional context about the issue:
|
||||
- Fetch the list of labels available in this repository. Use 'gh label list' bash command to fetch the labels. This will give you the labels you can use for triaging issues.
|
||||
- Fetch any comments on the issue using the `get_issue_comments` tool
|
||||
- **Search for duplicate and related issues**: Use the `search_issues` tool to find similar issues by searching for key terms from the issue title and description. Look for both open and closed issues that might be related or duplicates.
|
||||
|
||||
- Fetch the list of labels available in this repository using the `list_label` tool with `owner: "appwrite"` and `repo: "appwrite"` parameters. This will give you the labels you can use for triaging issues.
|
||||
- Fetch any comments on the issue using the `get_issue_comments` tool to understand recent activity
|
||||
- **Search for duplicate and related issues (repo first, then org-wide)**:
|
||||
- First search in this repository using the `search_issues` tool with a query like: `repo:appwrite/appwrite is:issue (is:open OR is:closed) <key terms>`.
|
||||
- Then perform an org-wide search across the entire Appwrite organization using: `org:appwrite is:issue (is:open OR is:closed) <key terms>`.
|
||||
- Prefer linking to OPEN issues when identifying potential duplicates; include CLOSED ones as related history when useful.
|
||||
|
||||
7. Analyze the issue content, considering:
|
||||
6. Analyze the issue content, considering:
|
||||
|
||||
- The issue title and description
|
||||
- The type of issue (bug report, feature request, question, etc.)
|
||||
@@ -78,38 +51,35 @@ You're a triage assistant for GitHub issues. Your task is to analyze issues that
|
||||
- User impact
|
||||
- Components affected
|
||||
|
||||
8. Write notes, ideas, nudges, resource links, debugging strategies and/or reproduction steps for the team to consider relevant to the issue.
|
||||
7. Write notes, ideas, nudges, resource links, debugging strategies and/or reproduction steps for the team to consider relevant to the issue.
|
||||
|
||||
9. Select appropriate labels from the available labels list:
|
||||
8. Select appropriate labels from the available labels list provided above:
|
||||
|
||||
- Choose labels that accurately reflect the issue's nature
|
||||
- Be specific but comprehensive
|
||||
- Select priority labels if you can determine urgency (high-priority, med-priority, or low-priority)
|
||||
- Consider platform labels (android, ios) if applicable
|
||||
- Search for similar issues. If you find a duplicate of another OPEN issue in THIS repository, you may use a "duplicate" label (if available) and reference the canonical issue.
|
||||
- If the closest match is in another repository within the Appwrite org, do NOT mark as duplicate here; instead, link it in your comment under a "Cross‑repo related issues" section.
|
||||
- Only select labels from the provided list
|
||||
- Don't apply the `good first issue` or `help wanted` labels
|
||||
- Search for similar issues, and if you find similar issues consider using a "duplicate" label if appropriate. Only do so if the issue is a duplicate of another OPEN issue.
|
||||
- Only select labels from the provided list above
|
||||
- It's okay to not add any labels if none are clearly applicable
|
||||
|
||||
10. Apply the selected labels:
|
||||
9. Apply the selected labels:
|
||||
|
||||
- Use the `update_issue` tool to apply the labels to the issue
|
||||
- DO NOT communicate directly with users
|
||||
- If no labels are clearly applicable, do not apply any labels
|
||||
|
||||
11. Add an issue comment to the issue with your analysis:
|
||||
10. Add an issue comment to the issue with your analysis:
|
||||
- Start with "🎯 Agentic Issue Triage"
|
||||
- Provide a brief summary of the issue
|
||||
- **If duplicate or related issues were found**, add sections listing them with links:
|
||||
- "### 🔗 Potentially Related Issues (this repo)" – bullet list of same-repo issues with titles and links
|
||||
- If applicable: "### 🌐 Cross-repo related issues (org: appwrite)" – bullet list including `owner/repo#number` with titles and links
|
||||
- **If duplicate or related issues were found**, add a section listing them with links (e.g., "### 🔗 Potentially Related Issues" followed by a bullet list of related issues with their titles and links)
|
||||
- Mention any relevant details that might help the team understand the issue better
|
||||
- Include any debugging strategies or reproduction steps if applicable
|
||||
- Suggest resources or links that might be helpful for resolving the issue or learning skills related to the issue or the particular area of the codebase affected by it
|
||||
- Mention any nudges or ideas that could help the team in addressing the issue
|
||||
- If appropriate break the issue down to sub-tasks and write a checklist of things to do
|
||||
- Use collapsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all sections except the short main summary at the top. For bolded section titles, wrap the text with `<strong>` and `</strong>` to make it bold.
|
||||
- Do not indicate/encourage a community member to submit a PR for the issue.
|
||||
- If you have possible reproduction steps, include them in the comment
|
||||
- If you have any debugging strategies, include them in the comment
|
||||
- If appropriate break the issue down to sub-tasks and write a checklist of things to do.
|
||||
- Use collapsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all sections except the short main summary at the top.
|
||||
|
||||
12. After processing all issues, provide a summary of how many issues were triaged (created or updated in the last 24 hours). If no issues matched the criteria, simply note that no issues needed triage.
|
||||
11. After processing all issues, provide a summary of how many issues were triaged. If no issues were created in the last 24 hours, simply note that no new issues needed triage.
|
||||
|
||||
@@ -98,6 +98,7 @@ RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
|
||||
# Enable Extensions
|
||||
RUN if [ "$DEBUG" = "true" ]; then cp /usr/src/code/dev/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini; fi
|
||||
RUN if [ "$DEBUG" = "true" ]; then mkdir -p /tmp/xdebug; fi
|
||||
RUN if [ "$DEBUG" = "true" ]; then apk add --update --no-cache openssh-client github-cli; fi
|
||||
RUN if [ "$DEBUG" = "false" ]; then rm -rf /usr/src/code/dev; fi
|
||||
RUN if [ "$DEBUG" = "false" ]; then rm -f /usr/local/lib/php/extensions/no-debug-non-zts-20230831/xdebug.so; fi
|
||||
|
||||
|
||||
@@ -202,6 +202,31 @@ return [
|
||||
]
|
||||
]
|
||||
],
|
||||
'tanstack-start' => [
|
||||
'key' => 'tanstack-start',
|
||||
'name' => 'TanStack Start',
|
||||
'screenshotSleep' => 3000,
|
||||
'buildRuntime' => 'node-22',
|
||||
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
|
||||
'bundleCommand' => 'bash /usr/local/server/helpers/tanstack-start/bundle.sh',
|
||||
'envCommand' => 'source /usr/local/server/helpers/tanstack-start/env.sh',
|
||||
'adapters' => [
|
||||
'ssr' => [
|
||||
'key' => 'ssr',
|
||||
'buildCommand' => 'npm run build',
|
||||
'installCommand' => 'npm install',
|
||||
'outputDirectory' => './dist',
|
||||
'startCommand' => 'bash helpers/tanstack-start/server.sh',
|
||||
],
|
||||
'static' => [
|
||||
'key' => 'static',
|
||||
'buildCommand' => 'npm run build',
|
||||
'installCommand' => 'npm install',
|
||||
'outputDirectory' => './dist/client',
|
||||
'startCommand' => 'bash helpers/server.sh',
|
||||
]
|
||||
]
|
||||
],
|
||||
'remix' => [
|
||||
'key' => 'remix',
|
||||
'name' => 'Remix',
|
||||
|
||||
@@ -2,6 +2,38 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://assets.appwrite.io/" crossorigin>
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta name="supported-color-schemes" content="light dark">
|
||||
<style type="text/css">
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
supported-color-schemes: light dark;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark ) {
|
||||
body {
|
||||
color: #616b7c !important;
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
a {
|
||||
color: currentColor !important;
|
||||
}
|
||||
a.button {
|
||||
color: #ffffff !important;
|
||||
background-color: {{accentColor}} !important;
|
||||
border-color: {{accentColor}} !important;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
color: #373b4d !important;
|
||||
}
|
||||
h4 {
|
||||
color: #4f5769 !important;
|
||||
}
|
||||
p.security-phrase:not(:empty), hr {
|
||||
border-color: #e8e9f0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
@@ -37,7 +69,6 @@
|
||||
font-family: "Inter", sans-serif;
|
||||
background-color: #ffffff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
a {
|
||||
color: currentColor;
|
||||
@@ -98,6 +129,7 @@
|
||||
color: #ffffff;
|
||||
border-radius: 8px;
|
||||
height: 48px;
|
||||
line-height: 24px;
|
||||
padding: 12px 20px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
@@ -153,7 +185,7 @@
|
||||
<tr>
|
||||
<td>
|
||||
<img
|
||||
height="32px"
|
||||
height="26px"
|
||||
src="{{logoUrl}}"
|
||||
alt="Appwrite logo"
|
||||
/>
|
||||
|
||||
@@ -2,6 +2,38 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://assets.appwrite.io/" crossorigin>
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta name="supported-color-schemes" content="light dark">
|
||||
<style type="text/css">
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
supported-color-schemes: light dark;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark ) {
|
||||
body {
|
||||
color: #616b7c !important;
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
a {
|
||||
color: currentColor !important;
|
||||
}
|
||||
a.button {
|
||||
color: #ffffff !important;
|
||||
background-color: #2D2D31 !important;
|
||||
border-color: #414146 !important;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
color: #373b4d !important;
|
||||
}
|
||||
h4 {
|
||||
color: #4f5769 !important;
|
||||
}
|
||||
p.security-phrase:not(:empty), hr {
|
||||
border-color: #e8e9f0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<p>{{hello}}</p>
|
||||
<p>{{body}}</p>
|
||||
<p>{{footer}}</p>
|
||||
<p style="margin-bottom: 32px">
|
||||
{{thanks}}
|
||||
<br/>
|
||||
{{signature}}
|
||||
</p>
|
||||
@@ -57,6 +57,21 @@
|
||||
"emails.recovery.thanks": "Thanks,",
|
||||
"emails.recovery.buttonText": "Reset password",
|
||||
"emails.recovery.signature": "{{project}} team",
|
||||
"emails.csvExport.success.subject": "Your CSV export is ready",
|
||||
"emails.csvExport.success.preview": "Your data export has been completed successfully.",
|
||||
"emails.csvExport.success.hello": "Hello {{user}},",
|
||||
"emails.csvExport.success.body": "Your CSV export is ready to download. Click the button below to download your data export.",
|
||||
"emails.csvExport.success.footer": "This download link will expire in 1 hour.",
|
||||
"emails.csvExport.success.thanks": "Thanks,",
|
||||
"emails.csvExport.success.buttonText": "Download CSV",
|
||||
"emails.csvExport.success.signature": "Appwrite team",
|
||||
"emails.csvExport.failure.subject": "Your CSV export failed - file too large",
|
||||
"emails.csvExport.failure.preview": "Your data export failed because the file size exceeds your plan limit.",
|
||||
"emails.csvExport.failure.hello": "Hello {{user}},",
|
||||
"emails.csvExport.failure.body": "Your CSV export could not be completed because the export file size ({{size}}MB) exceeds your plan limit. Please consider upgrading your plan or exporting a smaller dataset.",
|
||||
"emails.csvExport.failure.footer": "If you have any questions, please contact our support team.",
|
||||
"emails.csvExport.failure.thanks": "Thanks,",
|
||||
"emails.csvExport.failure.signature": "{{project}} team",
|
||||
"emails.invitation.subject": "Invitation to {{team}} Team at {{project}}",
|
||||
"emails.invitation.preview": "{{owner}} invited you to join {{team}} at {{project}}",
|
||||
"emails.invitation.hello": "Hello {{user}},",
|
||||
|
||||
+16
-16
@@ -11,7 +11,7 @@ return [
|
||||
[
|
||||
'key' => 'web',
|
||||
'name' => 'Web',
|
||||
'version' => '21.2.1',
|
||||
'version' => '21.4.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-web',
|
||||
'package' => 'https://www.npmjs.com/package/appwrite',
|
||||
'enabled' => true,
|
||||
@@ -60,7 +60,7 @@ return [
|
||||
[
|
||||
'key' => 'flutter',
|
||||
'name' => 'Flutter',
|
||||
'version' => '20.2.1',
|
||||
'version' => '20.3.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-flutter',
|
||||
'package' => 'https://pub.dev/packages/appwrite',
|
||||
'enabled' => true,
|
||||
@@ -79,7 +79,7 @@ return [
|
||||
[
|
||||
'key' => 'apple',
|
||||
'name' => 'Apple',
|
||||
'version' => '13.2.1',
|
||||
'version' => '13.4.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-apple',
|
||||
'package' => 'https://github.com/appwrite/sdk-for-apple',
|
||||
'enabled' => true,
|
||||
@@ -116,7 +116,7 @@ return [
|
||||
[
|
||||
'key' => 'android',
|
||||
'name' => 'Android',
|
||||
'version' => '11.2.1',
|
||||
'version' => '11.3.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-android',
|
||||
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android',
|
||||
'enabled' => true,
|
||||
@@ -139,7 +139,7 @@ return [
|
||||
[
|
||||
'key' => 'react-native',
|
||||
'name' => 'React Native',
|
||||
'version' => '0.17.1',
|
||||
'version' => '0.18.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-react-native',
|
||||
'package' => 'https://npmjs.com/package/react-native-appwrite',
|
||||
'enabled' => true,
|
||||
@@ -207,7 +207,7 @@ return [
|
||||
[
|
||||
'key' => 'web',
|
||||
'name' => 'Console',
|
||||
'version' => '0.1.1',
|
||||
'version' => '0.2.0',
|
||||
'url' => '',
|
||||
'package' => '',
|
||||
'enabled' => true,
|
||||
@@ -226,7 +226,7 @@ return [
|
||||
[
|
||||
'key' => 'cli',
|
||||
'name' => 'Command Line',
|
||||
'version' => '10.2.1',
|
||||
'version' => '11.1.1',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-cli',
|
||||
'package' => 'https://www.npmjs.com/package/appwrite-cli',
|
||||
'enabled' => true,
|
||||
@@ -262,7 +262,7 @@ return [
|
||||
[
|
||||
'key' => 'nodejs',
|
||||
'name' => 'Node.js',
|
||||
'version' => '20.2.1',
|
||||
'version' => '20.3.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-node',
|
||||
'package' => 'https://www.npmjs.com/package/node-appwrite',
|
||||
'enabled' => true,
|
||||
@@ -281,7 +281,7 @@ return [
|
||||
[
|
||||
'key' => 'php',
|
||||
'name' => 'PHP',
|
||||
'version' => '17.4.1',
|
||||
'version' => '18.0.1',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-php',
|
||||
'package' => 'https://packagist.org/packages/appwrite/appwrite',
|
||||
'enabled' => true,
|
||||
@@ -300,7 +300,7 @@ return [
|
||||
[
|
||||
'key' => 'python',
|
||||
'name' => 'Python',
|
||||
'version' => '13.4.1',
|
||||
'version' => '13.6.1',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-python',
|
||||
'package' => 'https://pypi.org/project/appwrite/',
|
||||
'enabled' => true,
|
||||
@@ -319,7 +319,7 @@ return [
|
||||
[
|
||||
'key' => 'ruby',
|
||||
'name' => 'Ruby',
|
||||
'version' => '19.2.1',
|
||||
'version' => '19.3.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-ruby',
|
||||
'package' => 'https://rubygems.org/gems/appwrite',
|
||||
'enabled' => true,
|
||||
@@ -338,7 +338,7 @@ return [
|
||||
[
|
||||
'key' => 'go',
|
||||
'name' => 'Go',
|
||||
'version' => 'v0.13.1',
|
||||
'version' => 'v0.14.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-go',
|
||||
'package' => 'https://github.com/appwrite/sdk-for-go',
|
||||
'enabled' => true,
|
||||
@@ -357,7 +357,7 @@ return [
|
||||
[
|
||||
'key' => 'dotnet',
|
||||
'name' => '.NET',
|
||||
'version' => '0.21.2',
|
||||
'version' => '0.22.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
|
||||
'package' => 'https://www.nuget.org/packages/Appwrite',
|
||||
'enabled' => true,
|
||||
@@ -376,7 +376,7 @@ return [
|
||||
[
|
||||
'key' => 'dart',
|
||||
'name' => 'Dart',
|
||||
'version' => '19.2.1',
|
||||
'version' => '19.3.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-dart',
|
||||
'package' => 'https://pub.dev/packages/dart_appwrite',
|
||||
'enabled' => true,
|
||||
@@ -395,7 +395,7 @@ return [
|
||||
[
|
||||
'key' => 'kotlin',
|
||||
'name' => 'Kotlin',
|
||||
'version' => '12.2.1',
|
||||
'version' => '12.3.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-kotlin',
|
||||
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin',
|
||||
'enabled' => true,
|
||||
@@ -418,7 +418,7 @@ return [
|
||||
[
|
||||
'key' => 'swift',
|
||||
'name' => 'Swift',
|
||||
'version' => '13.2.1',
|
||||
'version' => '13.3.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-swift',
|
||||
'package' => 'https://github.com/appwrite/sdk-for-swift',
|
||||
'enabled' => true,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,11 @@ use Utopia\System\System;
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$hostname = System::getEnv('_APP_DOMAIN', '');
|
||||
|
||||
// Temporary fix until we can set _APP_DOMAIN to "localhost" instead of "traefik"
|
||||
if (System::getEnv('_APP_ENV', 'development') === 'development') {
|
||||
$hostname = 'localhost';
|
||||
}
|
||||
|
||||
$url = $protocol . '://' . $hostname;
|
||||
|
||||
class UseCases
|
||||
@@ -19,6 +24,7 @@ class UseCases
|
||||
public const ECOMMERCE = 'ecommerce';
|
||||
public const DOCUMENTATION = 'documentation';
|
||||
public const BLOG = 'blog';
|
||||
public const AI = 'artificial intelligence';
|
||||
}
|
||||
|
||||
const TEMPLATE_FRAMEWORKS = [
|
||||
@@ -111,6 +117,16 @@ const TEMPLATE_FRAMEWORKS = [
|
||||
'outputDirectory' => './dist',
|
||||
'fallbackFile' => '+not-found.html',
|
||||
],
|
||||
'TANSTACK_START' => [
|
||||
'key' => 'tanstack-start',
|
||||
'name' => 'TanStack Start',
|
||||
'installCommand' => 'npm install',
|
||||
'buildCommand' => 'npm run build',
|
||||
'outputDirectory' => './dist',
|
||||
'buildRuntime' => 'node-22',
|
||||
'adapter' => 'ssr',
|
||||
'fallbackFile' => '',
|
||||
],
|
||||
'ANGULAR' => [
|
||||
'key' => 'angular',
|
||||
'name' => 'Angular',
|
||||
@@ -950,6 +966,50 @@ return [
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'key' => 'starter-for-tanstack-start',
|
||||
'name' => 'TanStack Start starter',
|
||||
'useCases' => [UseCases::STARTER],
|
||||
'tagline' => 'Simple TanStack Start application integrated with Appwrite SDK.',
|
||||
'score' => 9, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
|
||||
'screenshotDark' => $url . '/images/sites/templates/starter-for-tanstack-start-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/starter-for-tanstack-start-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('TANSTACK_START', [
|
||||
'providerRootDirectory' => './',
|
||||
]),
|
||||
],
|
||||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'starter-for-tanstack-start',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerVersion' => '0.1.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'VITE_APPWRITE_ENDPOINT',
|
||||
'description' => 'Endpoint of Appwrite server',
|
||||
'value' => '{apiEndpoint}',
|
||||
'placeholder' => '{apiEndpoint}',
|
||||
'required' => true,
|
||||
'type' => 'text'
|
||||
],
|
||||
[
|
||||
'name' => 'VITE_APPWRITE_PROJECT_ID',
|
||||
'description' => 'Your Appwrite project ID',
|
||||
'value' => '{projectId}',
|
||||
'placeholder' => '{projectId}',
|
||||
'required' => true,
|
||||
'type' => 'text'
|
||||
],
|
||||
[
|
||||
'name' => 'VITE_APPWRITE_PROJECT_NAME',
|
||||
'description' => 'Your Appwrite project name',
|
||||
'value' => '{projectName}',
|
||||
'placeholder' => '{projectName}',
|
||||
'required' => true,
|
||||
'type' => 'text'
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'key' => 'starter-for-nuxt',
|
||||
'name' => 'Nuxt starter',
|
||||
@@ -1327,6 +1387,25 @@ return [
|
||||
'providerVersion' => '0.3.*',
|
||||
'variables' => [],
|
||||
],
|
||||
[
|
||||
'key' => 'playground-for-tanstack-start',
|
||||
'name' => 'TanStack Start playground',
|
||||
'tagline' => 'A basic TanStack Start website without Appwrite SDK integration.',
|
||||
'score' => 1, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
|
||||
'useCases' => [UseCases::STARTER],
|
||||
'screenshotDark' => $url . '/images/sites/templates/playground-for-tanstack-start-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/playground-for-tanstack-start-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('TANSTACK_START', [
|
||||
'providerRootDirectory' => './tanstack-start/starter',
|
||||
]),
|
||||
],
|
||||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates-for-sites',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerVersion' => '0.5.*',
|
||||
'variables' => [],
|
||||
],
|
||||
[
|
||||
'key' => 'playground-for-react-native',
|
||||
'name' => 'React Native playground',
|
||||
@@ -1365,4 +1444,32 @@ return [
|
||||
'providerVersion' => '0.3.*',
|
||||
'variables' => []
|
||||
],
|
||||
[
|
||||
'key' => 'text-to-speech',
|
||||
'name' => 'Text-to-speech with ElevenLabs',
|
||||
'tagline' => 'Next.js app that transforms text into natural, human-like speech using ElevenLabs',
|
||||
'score' => 10, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
|
||||
'useCases' => [UseCases::AI],
|
||||
'screenshotDark' => $url . '/images/sites/templates/text-to-speech-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/text-to-speech-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('NEXTJS', [
|
||||
'providerRootDirectory' => './nextjs/text-to-speech',
|
||||
]),
|
||||
],
|
||||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates-for-sites',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerVersion' => '0.6.*',
|
||||
'variables' => [
|
||||
[
|
||||
'name' => 'ELEVENLABS_API_KEY',
|
||||
'description' => 'Your ElevenLabs API key',
|
||||
'value' => '',
|
||||
'placeholder' => 'sk_.....',
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
@@ -952,6 +952,16 @@ return [
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_BROWSER_HOST',
|
||||
'description' => 'The host used by Appwrite to communicate with the browser service for screenshots.',
|
||||
'introduction' => '1.8.0',
|
||||
'default' => 'http://appwrite-browser:3000/v1',
|
||||
'required' => false,
|
||||
'overwrite' => true,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_EXECUTOR_RUNTIME_NETWORK',
|
||||
'description' => 'Deprecated with 0.14.0, use \'OPEN_RUNTIMES_NETWORK\' instead.',
|
||||
|
||||
@@ -75,6 +75,14 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc
|
||||
$subject = $locale->getText("emails.sessionAlert.subject");
|
||||
$preview = $locale->getText("emails.sessionAlert.preview");
|
||||
$customTemplate = $project->getAttribute('templates', [])['email.sessionAlert-' . $locale->default] ?? [];
|
||||
$smtpBaseTemplate = $project->getAttribute('smtpBaseTemplate', 'email-base');
|
||||
|
||||
$validator = new FileName();
|
||||
if (!$validator->isValid($smtpBaseTemplate)) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid template path');
|
||||
}
|
||||
|
||||
$bodyTemplate = __DIR__ . '/../../config/locale/templates/' . $smtpBaseTemplate . '.tpl';
|
||||
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-session-alert.tpl');
|
||||
$message
|
||||
@@ -157,12 +165,25 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc
|
||||
'country' => $locale->getText('countries.' . $session->getAttribute('countryCode'), $locale->getText('locale.country.unknown')),
|
||||
];
|
||||
|
||||
if ($smtpBaseTemplate === APP_BRANDED_EMAIL_BASE_TEMPLATE) {
|
||||
$emailVariables = array_merge($emailVariables, [
|
||||
'accentColor' => APP_EMAIL_ACCENT_COLOR,
|
||||
'logoUrl' => APP_EMAIL_LOGO_URL,
|
||||
'twitterUrl' => APP_SOCIAL_TWITTER,
|
||||
'discordUrl' => APP_SOCIAL_DISCORD,
|
||||
'githubUrl' => APP_SOCIAL_GITHUB_APPWRITE,
|
||||
'termsUrl' => APP_EMAIL_TERMS_URL,
|
||||
'privacyUrl' => APP_EMAIL_PRIVACY_URL,
|
||||
]);
|
||||
}
|
||||
|
||||
$email = $user->getAttribute('email');
|
||||
|
||||
$queueForMails
|
||||
->setSubject($subject)
|
||||
->setPreview($preview)
|
||||
->setBody($body)
|
||||
->setBodyTemplate($bodyTemplate)
|
||||
->setVariables($emailVariables)
|
||||
->setRecipient($email)
|
||||
->trigger();
|
||||
@@ -2814,12 +2835,13 @@ App::get('/v1/account/logs')
|
||||
contentType: ContentType::JSON,
|
||||
))
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject) {
|
||||
->action(function (array $queries, bool $includeTotal, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject) {
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
@@ -2864,7 +2886,7 @@ App::get('/v1/account/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByUser($user->getSequence(), $queries),
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence(), $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -5211,10 +5233,11 @@ App::get('/v1/account/identities')
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Identities::ALLOWED_ATTRIBUTES), true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, Response $response, Document $user, Database $dbForProject) {
|
||||
->action(function (array $queries, bool $includeTotal, Response $response, Document $user, Database $dbForProject) {
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
@@ -5255,7 +5278,7 @@ App::get('/v1/account/identities')
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
$total = $dbForProject->count('identities', $filterQueries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('identities', $filterQueries, APP_LIMIT_COUNT) : 0;
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'identities' => $results,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Event\StatsUsage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
@@ -23,6 +24,8 @@ use Utopia\Fetch\Client;
|
||||
use Utopia\Image\Image;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\HexColor;
|
||||
use Utopia\Validator\Range;
|
||||
@@ -635,6 +638,187 @@ App::get('/v1/avatars/initials')
|
||||
->file($image->getImageBlob());
|
||||
});
|
||||
|
||||
App::get('/v1/avatars/screenshots')
|
||||
->desc('Get webpage screenshot')
|
||||
->groups(['api', 'avatars'])
|
||||
->label('scope', 'avatars.read')
|
||||
->label('usage.metric', METRIC_AVATARS_SCREENSHOTS_GENERATED)
|
||||
->label('abuse-limit', 60)
|
||||
->label('cache', true)
|
||||
->label('cache.resourceType', 'avatar/screenshot')
|
||||
->label('cache.resource', 'screenshot/{request.url}/{request.width}/{request.height}/{request.scale}/{request.theme}/{request.userAgent}/{request.fullpage}/{request.locale}/{request.timezone}/{request.latitude}/{request.longitude}/{request.accuracy}/{request.touch}/{request.permissions}/{request.sleep}/{request.quality}/{request.output}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'avatars',
|
||||
group: null,
|
||||
name: 'getScreenshot',
|
||||
description: '/docs/references/avatars/get-screenshot.md',
|
||||
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
|
||||
type: MethodType::LOCATION,
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_NONE,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::IMAGE_PNG
|
||||
))
|
||||
->param('url', '', new URL(['http', 'https']), 'Website URL which you want to capture.')
|
||||
->param('headers', [], new Assoc(), 'HTTP headers to send with the browser request. Defaults to empty.', true)
|
||||
->param('viewportWidth', 1280, new Range(1, 1920), 'Browser viewport width. Pass an integer between 1 to 1920. Defaults to 1280.', true)
|
||||
->param('viewportHeight', 720, new Range(1, 1080), 'Browser viewport height. Pass an integer between 1 to 1080. Defaults to 720.', true)
|
||||
->param('scale', 1, new Range(0.1, 3, Range::TYPE_FLOAT), 'Browser scale factor. Pass a number between 0.1 to 3. Defaults to 1.', true)
|
||||
->param('theme', 'light', new WhiteList(['light', 'dark']), 'Browser theme. Pass "light" or "dark". Defaults to "light".', true)
|
||||
->param('userAgent', '', new Text(512), 'Custom user agent string. Defaults to browser default.', true)
|
||||
->param('fullpage', false, new Boolean(true), 'Capture full page scroll. Pass 0 for viewport only, or 1 for full page. Defaults to 0.', true)
|
||||
->param('locale', '', new Text(10), 'Browser locale (e.g., "en-US", "fr-FR"). Defaults to browser default.', true)
|
||||
->param('timezone', '', new WhiteList(timezone_identifiers_list()), 'IANA timezone identifier (e.g., "America/New_York", "Europe/London"). Defaults to browser default.', true)
|
||||
->param('latitude', 0, new Range(-90, 90, Range::TYPE_FLOAT), 'Geolocation latitude. Pass a number between -90 to 90. Defaults to 0.', true)
|
||||
->param('longitude', 0, new Range(-180, 180, Range::TYPE_FLOAT), 'Geolocation longitude. Pass a number between -180 to 180. Defaults to 0.', true)
|
||||
->param('accuracy', 0, new Range(0, 100000, Range::TYPE_FLOAT), 'Geolocation accuracy in meters. Pass a number between 0 to 100000. Defaults to 0.', true)
|
||||
->param('touch', false, new Boolean(true), 'Enable touch support. Pass 0 for no touch, or 1 for touch enabled. Defaults to 0.', true)
|
||||
->param('permissions', [], new ArrayList(new WhiteList(['geolocation', 'camera', 'microphone', 'notifications', 'midi', 'push', 'clipboard-read', 'clipboard-write', 'payment-handler', 'usb', 'bluetooth', 'accelerometer', 'gyroscope', 'magnetometer', 'ambient-light-sensor', 'background-sync', 'persistent-storage', 'screen-wake-lock', 'web-share', 'xr-spatial-tracking'])), 'Browser permissions to grant. Pass an array of permission names like ["geolocation", "camera", "microphone"]. Defaults to empty.', true)
|
||||
->param('sleep', 0, new Range(0, 10), 'Wait time in seconds before taking the screenshot. Pass an integer between 0 to 10. Defaults to 0.', true)
|
||||
->param('width', 0, new Range(0, 2000), 'Output image width. Pass 0 to use original width, or an integer between 1 to 2000. Defaults to 0 (original width).', true)
|
||||
->param('height', 0, new Range(0, 2000), 'Output image height. Pass 0 to use original height, or an integer between 1 to 2000. Defaults to 0 (original height).', true)
|
||||
->param('quality', -1, new Range(-1, 100), 'Screenshot quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.', true)
|
||||
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true)
|
||||
->inject('response')
|
||||
->inject('queueForStatsUsage')
|
||||
->action(function (string $url, array $headers, int $viewportWidth, int $viewportHeight, float $scale, string $theme, string $userAgent, bool $fullpage, string $locale, string $timezone, float $latitude, float $longitude, float $accuracy, bool $touch, array $permissions, int $sleep, int $width, int $height, int $quality, string $output, Response $response, StatsUsage $queueForStatsUsage) {
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
$domain = new Domain(\parse_url($url, PHP_URL_HOST));
|
||||
|
||||
if (!$domain->isKnown()) {
|
||||
throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED);
|
||||
}
|
||||
|
||||
$client = new Client();
|
||||
$client->setTimeout(30);
|
||||
$client->addHeader('content-type', Client::CONTENT_TYPE_APPLICATION_JSON);
|
||||
|
||||
// Convert indexed array to empty array (should not happen due to Assoc validator)
|
||||
if (is_array($headers) && count($headers) > 0 && array_keys($headers) === range(0, count($headers) - 1)) {
|
||||
$headers = [];
|
||||
}
|
||||
|
||||
// Create a new object to ensure proper JSON serialization
|
||||
$headersObject = new \stdClass();
|
||||
foreach ($headers as $key => $value) {
|
||||
$headersObject->$key = $value;
|
||||
}
|
||||
|
||||
// Create the config with headers as an object
|
||||
// The custom browser service accepts: url, theme, headers, sleep, viewport, userAgent, fullPage, locale, timezoneId, geolocation, hasTouch, scale
|
||||
$config = [
|
||||
'url' => $url,
|
||||
'theme' => $theme,
|
||||
'headers' => $headersObject,
|
||||
'sleep' => $sleep * 1000, // Convert seconds to milliseconds
|
||||
'waitUntil' => 'load',
|
||||
'viewport' => [
|
||||
'width' => $viewportWidth,
|
||||
'height' => $viewportHeight
|
||||
]
|
||||
];
|
||||
|
||||
// Add scale if not default
|
||||
if ($scale != 1) {
|
||||
$config['deviceScaleFactor'] = $scale;
|
||||
}
|
||||
|
||||
// Add optional parameters that were set, preserving arrays as arrays
|
||||
if (!empty($userAgent)) {
|
||||
$config['userAgent'] = $userAgent;
|
||||
}
|
||||
|
||||
if ($fullpage) {
|
||||
$config['fullPage'] = true;
|
||||
}
|
||||
|
||||
if (!empty($locale)) {
|
||||
$config['locale'] = $locale;
|
||||
}
|
||||
|
||||
if (!empty($timezone)) {
|
||||
$config['timezoneId'] = $timezone;
|
||||
}
|
||||
|
||||
// Add geolocation if any coordinates are provided
|
||||
if ($latitude != 0 || $longitude != 0) {
|
||||
$config['geolocation'] = [
|
||||
'latitude' => $latitude,
|
||||
'longitude' => $longitude,
|
||||
'accuracy' => $accuracy
|
||||
];
|
||||
}
|
||||
|
||||
if ($touch) {
|
||||
$config['hasTouch'] = true;
|
||||
}
|
||||
|
||||
// Add permissions if provided (preserve as array)
|
||||
if (!empty($permissions)) {
|
||||
$config['permissions'] = $permissions; // Keep as array
|
||||
}
|
||||
|
||||
try {
|
||||
$browserEndpoint = System::getEnv('_APP_BROWSER_HOST', 'http://appwrite-browser:3000/v1');
|
||||
|
||||
$fetchResponse = $client->fetch(
|
||||
url: $browserEndpoint . '/screenshots',
|
||||
method: 'POST',
|
||||
body: $config
|
||||
);
|
||||
|
||||
if ($fetchResponse->getStatusCode() >= 400) {
|
||||
throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED, 'Screenshot service failed: ' . $fetchResponse->getBody());
|
||||
}
|
||||
|
||||
$screenshot = $fetchResponse->getBody();
|
||||
|
||||
if (empty($screenshot)) {
|
||||
throw new Exception(Exception::AVATAR_IMAGE_NOT_FOUND, 'Screenshot not generated');
|
||||
}
|
||||
|
||||
// Determine if image processing is needed
|
||||
$needsProcessing = ($width > 0 || $height > 0) || $quality !== -1 || !empty($output);
|
||||
|
||||
if ($needsProcessing) {
|
||||
// Process image with cropping, quality adjustment, or format conversion
|
||||
$image = new Image($screenshot);
|
||||
|
||||
$image->crop($width, $height);
|
||||
|
||||
$output = $output ?: 'png'; // Default to PNG if not specified
|
||||
$resizedScreenshot = $image->output($output, $quality);
|
||||
unset($image);
|
||||
} else {
|
||||
// Return original screenshot without processing
|
||||
$resizedScreenshot = $screenshot;
|
||||
$output = 'png'; // Screenshots are typically PNG by default
|
||||
}
|
||||
|
||||
// Set content type based on output format
|
||||
$outputs = Config::getParam('storage-outputs');
|
||||
$contentType = $outputs[$output] ?? $outputs['png'];
|
||||
|
||||
$queueForStatsUsage->addMetric(METRIC_AVATARS_SCREENSHOTS_GENERATED, 1);
|
||||
|
||||
$response
|
||||
->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
|
||||
->setContentType($contentType)
|
||||
->file($resizedScreenshot);
|
||||
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED, 'Screenshot generation failed: ' . $th->getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
App::get('/v1/cards/cloud')
|
||||
->desc('Get front Of Cloud Card')
|
||||
->groups(['api', 'avatars'])
|
||||
|
||||
@@ -74,6 +74,7 @@ App::get('/v1/console/variables')
|
||||
// Combine CAA domain with most common flags and tag (no parameters)
|
||||
'_APP_DOMAIN_TARGET_CAA' => '0 issue "' . System::getEnv('_APP_DOMAIN_TARGET_CAA') . '"',
|
||||
'_APP_STORAGE_LIMIT' => +System::getEnv('_APP_STORAGE_LIMIT'),
|
||||
'_APP_COMPUTE_BUILD_TIMEOUT' => +System::getEnv('_APP_COMPUTE_BUILD_TIMEOUT'),
|
||||
'_APP_COMPUTE_SIZE_LIMIT' => +System::getEnv('_APP_COMPUTE_SIZE_LIMIT'),
|
||||
'_APP_USAGE_STATS' => System::getEnv('_APP_USAGE_STATS'),
|
||||
'_APP_VCS_ENABLED' => $isVcsEnabled,
|
||||
|
||||
@@ -37,7 +37,6 @@ App::get('/v1/locale')
|
||||
$currencies = Config::getParam('locale-currencies');
|
||||
$output = [];
|
||||
$ip = $request->getIP();
|
||||
$time = (60 * 60 * 24 * 45); // 45 days cache
|
||||
|
||||
$output['ip'] = $ip;
|
||||
|
||||
@@ -68,10 +67,6 @@ App::get('/v1/locale')
|
||||
$output['currency'] = $currency;
|
||||
}
|
||||
|
||||
$response
|
||||
->addHeader('Cache-Control', 'public, max-age=' . $time)
|
||||
->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
|
||||
;
|
||||
$response->dynamic(new Document($output), Response::MODEL_LOCALE);
|
||||
});
|
||||
|
||||
|
||||
@@ -231,6 +231,88 @@ App::post('/v1/messaging/providers/sendgrid')
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::post('/v1/messaging/providers/resend')
|
||||
->desc('Create Resend provider')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'provider.create')
|
||||
->label('audits.resource', 'provider/{response.$id}')
|
||||
->label('event', 'providers.[providerId].create')
|
||||
->label('scope', 'providers.write')
|
||||
->label('resourceType', RESOURCE_TYPE_PROVIDERS)
|
||||
->label('sdk', new Method(
|
||||
namespace: 'messaging',
|
||||
group: 'providers',
|
||||
name: 'createResendProvider',
|
||||
description: '/docs/references/messaging/create-resend-provider.md',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_CREATED,
|
||||
model: Response::MODEL_PROVIDER,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('apiKey', '', new Text(0), 'Resend API key.', true)
|
||||
->param('fromName', '', new Text(128, 0), 'Sender Name.', true)
|
||||
->param('fromEmail', '', new Email(), 'Sender email address.', true)
|
||||
->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name.', true)
|
||||
->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email.', true)
|
||||
->param('enabled', null, new Boolean(), 'Set as enabled.', true)
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $providerId, string $name, string $apiKey, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) {
|
||||
$providerId = $providerId == 'unique()' ? ID::unique() : $providerId;
|
||||
|
||||
$credentials = [];
|
||||
|
||||
if (!empty($apiKey)) {
|
||||
$credentials['apiKey'] = $apiKey;
|
||||
}
|
||||
|
||||
$options = [
|
||||
'fromName' => $fromName,
|
||||
'fromEmail' => $fromEmail,
|
||||
'replyToName' => $replyToName,
|
||||
'replyToEmail' => $replyToEmail,
|
||||
];
|
||||
|
||||
if (
|
||||
$enabled === true
|
||||
&& !empty($fromEmail)
|
||||
&& \array_key_exists('apiKey', $credentials)
|
||||
) {
|
||||
$enabled = true;
|
||||
} else {
|
||||
$enabled = false;
|
||||
}
|
||||
|
||||
$provider = new Document([
|
||||
'$id' => $providerId,
|
||||
'name' => $name,
|
||||
'provider' => 'resend',
|
||||
'type' => MESSAGE_TYPE_EMAIL,
|
||||
'enabled' => $enabled,
|
||||
'credentials' => $credentials,
|
||||
'options' => $options,
|
||||
]);
|
||||
|
||||
try {
|
||||
$provider = $dbForProject->createDocument('providers', $provider);
|
||||
} catch (DuplicateException) {
|
||||
throw new Exception(Exception::PROVIDER_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
->setParam('providerId', $provider->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::post('/v1/messaging/providers/smtp')
|
||||
->desc('Create SMTP provider')
|
||||
->groups(['api', 'messaging'])
|
||||
@@ -985,9 +1067,10 @@ App::get('/v1/messaging/providers')
|
||||
))
|
||||
->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (array $queries, string $search, Database $dbForProject, Response $response) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -1023,7 +1106,7 @@ App::get('/v1/messaging/providers')
|
||||
}
|
||||
try {
|
||||
$providers = $dbForProject->find('providers', $queries);
|
||||
$total = $dbForProject->count('providers', $queries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('providers', $queries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
@@ -1053,11 +1136,12 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $providerId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->action(function (string $providerId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
@@ -1125,7 +1209,7 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByResource($resource, $queries),
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -1372,6 +1456,104 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId')
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/resend/:providerId')
|
||||
->desc('Update Resend provider')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'provider.update')
|
||||
->label('audits.resource', 'provider/{response.$id}')
|
||||
->label('event', 'providers.[providerId].update')
|
||||
->label('scope', 'providers.write')
|
||||
->label('resourceType', RESOURCE_TYPE_PROVIDERS)
|
||||
->label('sdk', new Method(
|
||||
namespace: 'messaging',
|
||||
group: 'providers',
|
||||
name: 'updateResendProvider',
|
||||
description: '/docs/references/messaging/update-resend-provider.md',
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_PROVIDER,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('enabled', null, new Boolean(), 'Set as enabled.', true)
|
||||
->param('apiKey', '', new Text(0), 'Resend API key.', true)
|
||||
->param('fromName', '', new Text(128), 'Sender Name.', true)
|
||||
->param('fromEmail', '', new Email(), 'Sender email address.', true)
|
||||
->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name.', true)
|
||||
->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email.', true)
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $providerId, string $name, ?bool $enabled, string $apiKey, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, Event $queueForEvents, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'resend') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE);
|
||||
}
|
||||
|
||||
if (!empty($name)) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
$options = $provider->getAttribute('options');
|
||||
|
||||
if (!empty($fromName)) {
|
||||
$options['fromName'] = $fromName;
|
||||
}
|
||||
|
||||
if (!empty($fromEmail)) {
|
||||
$options['fromEmail'] = $fromEmail;
|
||||
}
|
||||
|
||||
if (!empty($replyToName)) {
|
||||
$options['replyToName'] = $replyToName;
|
||||
}
|
||||
|
||||
if (!empty($replyToEmail)) {
|
||||
$options['replyToEmail'] = $replyToEmail;
|
||||
}
|
||||
|
||||
$provider->setAttribute('options', $options);
|
||||
|
||||
if (!empty($apiKey)) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'apiKey' => $apiKey,
|
||||
]);
|
||||
}
|
||||
|
||||
if (!\is_null($enabled)) {
|
||||
if ($enabled) {
|
||||
if (
|
||||
\array_key_exists('apiKey', $provider->getAttribute('credentials')) &&
|
||||
\array_key_exists('fromEmail', $provider->getAttribute('options'))
|
||||
) {
|
||||
$provider->setAttribute('enabled', true);
|
||||
} else {
|
||||
throw new Exception(Exception::PROVIDER_MISSING_CREDENTIALS);
|
||||
}
|
||||
} else {
|
||||
$provider->setAttribute('enabled', false);
|
||||
}
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
|
||||
$queueForEvents
|
||||
->setParam('providerId', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/smtp/:providerId')
|
||||
->desc('Update SMTP provider')
|
||||
->groups(['api', 'messaging'])
|
||||
@@ -2292,9 +2474,10 @@ App::get('/v1/messaging/topics')
|
||||
))
|
||||
->param('queries', [], new Topics(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Topics::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (array $queries, string $search, Database $dbForProject, Response $response) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -2330,7 +2513,7 @@ App::get('/v1/messaging/topics')
|
||||
}
|
||||
try {
|
||||
$topics = $dbForProject->find('topics', $queries);
|
||||
$total = $dbForProject->count('topics', $queries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('topics', $queries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
@@ -2360,11 +2543,12 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $topicId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->action(function (string $topicId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
$topic = $dbForProject->getDocument('topics', $topicId);
|
||||
|
||||
if ($topic->isEmpty()) {
|
||||
@@ -2433,7 +2617,7 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByResource($resource, $queries),
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -2693,9 +2877,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
|
||||
->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.')
|
||||
->param('queries', [], new Subscribers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $topicId, array $queries, string $search, Database $dbForProject, Response $response) {
|
||||
->action(function (string $topicId, array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -2757,7 +2942,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
|
||||
$response
|
||||
->dynamic(new Document([
|
||||
'subscribers' => $subscribers,
|
||||
'total' => $dbForProject->count('subscribers', $queries, APP_LIMIT_COUNT),
|
||||
'total' => $includeTotal ? $dbForProject->count('subscribers', $queries, APP_LIMIT_COUNT) : 0,
|
||||
]), Response::MODEL_SUBSCRIBER_LIST);
|
||||
});
|
||||
|
||||
@@ -2781,11 +2966,12 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
))
|
||||
->param('subscriberId', '', new UID(), 'Subscriber ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $subscriberId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->action(function (string $subscriberId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
$subscriber = $dbForProject->getDocument('subscribers', $subscriberId);
|
||||
|
||||
if ($subscriber->isEmpty()) {
|
||||
@@ -2854,7 +3040,7 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByResource($resource, $queries),
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -3511,9 +3697,10 @@ App::get('/v1/messaging/messages')
|
||||
))
|
||||
->param('queries', [], new Messages(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Messages::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (array $queries, string $search, Database $dbForProject, Response $response) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -3549,7 +3736,7 @@ App::get('/v1/messaging/messages')
|
||||
}
|
||||
try {
|
||||
$messages = $dbForProject->find('messages', $queries);
|
||||
$total = $dbForProject->count('messages', $queries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('messages', $queries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
@@ -3579,11 +3766,12 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $messageId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->action(function (string $messageId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
$message = $dbForProject->getDocument('messages', $messageId);
|
||||
|
||||
if ($message->isEmpty()) {
|
||||
@@ -3652,7 +3840,7 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByResource($resource, $queries),
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -3677,9 +3865,10 @@ App::get('/v1/messaging/messages/:messageId/targets')
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('queries', [], new Targets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Targets::ALLOWED_ATTRIBUTES), true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $messageId, array $queries, Response $response, Database $dbForProject) {
|
||||
->action(function (string $messageId, array $queries, bool $includeTotal, Response $response, Database $dbForProject) {
|
||||
$message = $dbForProject->getDocument('messages', $messageId);
|
||||
|
||||
if ($message->isEmpty()) {
|
||||
@@ -3729,7 +3918,7 @@ App::get('/v1/messaging/messages/:messageId/targets')
|
||||
}
|
||||
try {
|
||||
$targets = $dbForProject->find('targets', $queries);
|
||||
$total = $dbForProject->count('targets', $queries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('targets', $queries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Migration;
|
||||
use Appwrite\Extend\Exception;
|
||||
@@ -20,6 +19,7 @@ use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries\Documents;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Migration\Resource;
|
||||
@@ -307,7 +307,8 @@ App::post('/v1/migrations/nhost')
|
||||
->dynamic($migration, Response::MODEL_MIGRATION);
|
||||
});
|
||||
|
||||
App::post('/v1/migrations/csv')
|
||||
App::post('/v1/migrations/csv/imports')
|
||||
->alias('/v1/migrations/csv')
|
||||
->groups(['api', 'migrations'])
|
||||
->desc('Import documents from a CSV')
|
||||
->label('scope', 'migrations.write')
|
||||
@@ -316,8 +317,8 @@ App::post('/v1/migrations/csv')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'migrations',
|
||||
group: null,
|
||||
name: 'createCsvMigration',
|
||||
description: '/docs/references/migrations/migration-csv.md',
|
||||
name: 'createCSVImport',
|
||||
description: '/docs/references/migrations/migration-csv-import.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
@@ -335,15 +336,23 @@ App::post('/v1/migrations/csv')
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('deviceForFiles')
|
||||
->inject('deviceForImports')
|
||||
->inject('deviceForMigrations')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForMigrations')
|
||||
->action(function (string $bucketId, string $fileId, string $resourceId, bool $internalFile, Response $response, Database $dbForProject, Database $dbForPlatform, Document $project, Device $deviceForFiles, Device $deviceForImports, Event $queueForEvents, Migration $queueForMigrations) {
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
if ($internalFile && !$isPrivilegedUser) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
->action(function (
|
||||
string $bucketId,
|
||||
string $fileId,
|
||||
string $resourceId,
|
||||
bool $internalFile,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Device $deviceForFiles,
|
||||
Device $deviceForMigrations,
|
||||
Event $queueForEvents,
|
||||
Migration $queueForMigrations
|
||||
) {
|
||||
$bucket = Authorization::skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) {
|
||||
if ($internalFile) {
|
||||
return $dbForPlatform->getDocument('buckets', 'default');
|
||||
@@ -351,7 +360,7 @@ App::post('/v1/migrations/csv')
|
||||
return $dbForProject->getDocument('buckets', $bucketId);
|
||||
});
|
||||
|
||||
if ($bucket->isEmpty() || (!$isAPIKey && !$isPrivilegedUser)) {
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -365,18 +374,17 @@ App::post('/v1/migrations/csv')
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
|
||||
}
|
||||
|
||||
// no encryption, compression on files above 20MB.
|
||||
// No encryption or compression on files above 20MB.
|
||||
$hasEncryption = !empty($file->getAttribute('openSSLCipher'));
|
||||
$compression = $file->getAttribute('algorithm', Compression::NONE);
|
||||
$hasCompression = $compression !== Compression::NONE;
|
||||
|
||||
$migrationId = ID::unique();
|
||||
$newPath = $deviceForImports->getPath($migrationId . '_' . $fileId . '.csv');
|
||||
$newPath = $deviceForMigrations->getPath($migrationId . '_' . $fileId . '.csv');
|
||||
|
||||
if ($hasEncryption || $hasCompression) {
|
||||
$source = $deviceForFiles->read($path);
|
||||
|
||||
// 1. decrypt
|
||||
if ($hasEncryption) {
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
@@ -388,7 +396,6 @@ App::post('/v1/migrations/csv')
|
||||
);
|
||||
}
|
||||
|
||||
// 2. decompress
|
||||
if ($hasCompression) {
|
||||
switch ($compression) {
|
||||
case Compression::ZSTD:
|
||||
@@ -400,15 +407,15 @@ App::post('/v1/migrations/csv')
|
||||
}
|
||||
}
|
||||
|
||||
// manual write after decryption and/or decompression
|
||||
if (! $deviceForImports->write($newPath, $source, 'text/csv')) {
|
||||
throw new \Exception("Unable to copy file");
|
||||
// Manual write after decryption and/or decompression
|
||||
if (!$deviceForMigrations->write($newPath, $source, 'text/csv')) {
|
||||
throw new \Exception('Unable to copy file');
|
||||
}
|
||||
} elseif (! $deviceForFiles->transfer($path, $newPath, $deviceForImports)) {
|
||||
throw new \Exception("Unable to copy file");
|
||||
} elseif (!$deviceForFiles->transfer($path, $newPath, $deviceForMigrations)) {
|
||||
throw new \Exception('Unable to copy file');
|
||||
}
|
||||
|
||||
$fileSize = $deviceForImports->getFileSize($newPath);
|
||||
$fileSize = $deviceForMigrations->getFileSize($newPath);
|
||||
$resources = Transfer::extractServices([Transfer::GROUP_DATABASES]);
|
||||
|
||||
$migration = $dbForProject->createDocument('migrations', new Document([
|
||||
@@ -441,6 +448,136 @@ App::post('/v1/migrations/csv')
|
||||
->dynamic($migration, Response::MODEL_MIGRATION);
|
||||
});
|
||||
|
||||
App::post('/v1/migrations/csv/exports')
|
||||
->groups(['api', 'migrations'])
|
||||
->desc('Export documents to CSV')
|
||||
->label('scope', 'migrations.write')
|
||||
->label('event', 'migrations.[migrationId].create')
|
||||
->label('audits.event', 'migration.create')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'migrations',
|
||||
group: null,
|
||||
name: 'createCSVExport',
|
||||
description: '/docs/references/migrations/migration-csv-export.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_ACCEPTED,
|
||||
model: Response::MODEL_MIGRATION,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('resourceId', null, new CompoundUID(), 'Composite ID in the format {databaseId:collectionId}, identifying a collection within a database to export.')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID where the exported CSV will be stored.')
|
||||
->param('filename', '', new Text(255), 'The name of the file to be created for the export, excluding the .csv extension.')
|
||||
->param('columns', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of attributes to export. If empty, all attributes will be exported. You can use the `*` wildcard to export all attributes from the collection.', true)
|
||||
->param('queries', [], new ArrayList(new Text(0)), 'Array of query strings generated using the Query class provided by the SDK to filter documents to export. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
|
||||
->param('delimiter', ',', new Text(1), 'The character that separates each column value. Default is comma.', true)
|
||||
->param('enclosure', '"', new Text(1), 'The character that encloses each column value. Default is double quotes.', true)
|
||||
->param('escape', '"', new Text(1), 'The escape character for the enclosure character. Default is double quotes.', true)
|
||||
->param('header', true, new Boolean(), 'Whether to include the header row with column names. Default is true.', true)
|
||||
->param('notify', true, new Boolean(), 'Set to true to receive an email when the export is complete. Default is true.', true)
|
||||
->inject('user')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForMigrations')
|
||||
->action(function (
|
||||
string $resourceId,
|
||||
string $bucketId,
|
||||
string $filename,
|
||||
array $columns,
|
||||
array $queries,
|
||||
string $delimiter,
|
||||
string $enclosure,
|
||||
string $escape,
|
||||
bool $header,
|
||||
bool $notify,
|
||||
Document $user,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Document $project,
|
||||
Event $queueForEvents,
|
||||
Migration $queueForMigrations
|
||||
) {
|
||||
try {
|
||||
$parsedQueries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
[$databaseId, $collectionId] = \explode(':', $resourceId, 2);
|
||||
if (empty($databaseId)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
if (empty($collectionId)) {
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId));
|
||||
if ($collection->isEmpty()) {
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$validator = new Documents(
|
||||
attributes: $collection->getAttribute('attributes', []),
|
||||
indexes: $collection->getAttribute('indexes', []),
|
||||
idAttributeType: $dbForProject->getAdapter()->getIdAttributeType(),
|
||||
);
|
||||
|
||||
if (!$validator->isValid($parsedQueries)) {
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
|
||||
}
|
||||
|
||||
$migration = $dbForProject->createDocument('migrations', new Document([
|
||||
'$id' => ID::unique(),
|
||||
'status' => 'pending',
|
||||
'stage' => 'init',
|
||||
'source' => Appwrite::getName(),
|
||||
'destination' => CSV::getName(),
|
||||
'resources' => Transfer::extractServices([Transfer::GROUP_DATABASES]),
|
||||
'resourceId' => $resourceId,
|
||||
'resourceType' => Resource::TYPE_DATABASE,
|
||||
'statusCounters' => '{}',
|
||||
'resourceData' => '{}',
|
||||
'errors' => [],
|
||||
'options' => [
|
||||
'bucketId' => $bucketId,
|
||||
'filename' => $filename,
|
||||
'columns' => $columns,
|
||||
'queries' => $queries,
|
||||
'delimiter' => $delimiter,
|
||||
'enclosure' => $enclosure,
|
||||
'escape' => $escape,
|
||||
'header' => $header,
|
||||
'notify' => $notify,
|
||||
'userInternalId' => $user->getSequence(),
|
||||
],
|
||||
]));
|
||||
|
||||
$queueForEvents->setParam('migrationId', $migration->getId());
|
||||
|
||||
$queueForMigrations
|
||||
->setMigration($migration)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
|
||||
->dynamic($migration, Response::MODEL_MIGRATION);
|
||||
});
|
||||
|
||||
App::get('/v1/migrations')
|
||||
->groups(['api', 'migrations'])
|
||||
->desc('List migrations')
|
||||
@@ -460,9 +597,10 @@ App::get('/v1/migrations')
|
||||
))
|
||||
->param('queries', [], new Migrations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Migrations::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -501,7 +639,7 @@ App::get('/v1/migrations')
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
try {
|
||||
$migrations = $dbForProject->find('migrations', $queries);
|
||||
$total = $dbForProject->count('migrations', $filterQueries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('migrations', $filterQueries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
|
||||
@@ -1234,9 +1234,10 @@ App::get('/v1/projects/:projectId/webhooks')
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, Response $response, Database $dbForPlatform) {
|
||||
->action(function (string $projectId, bool $includeTotal, Response $response, Database $dbForPlatform) {
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
@@ -1251,7 +1252,7 @@ App::get('/v1/projects/:projectId/webhooks')
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'webhooks' => $webhooks,
|
||||
'total' => count($webhooks),
|
||||
'total' => $includeTotal ? count($webhooks) : 0,
|
||||
]), Response::MODEL_WEBHOOK_LIST);
|
||||
});
|
||||
|
||||
@@ -1531,9 +1532,10 @@ App::get('/v1/projects/:projectId/keys')
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, Response $response, Database $dbForPlatform) {
|
||||
->action(function (string $projectId, bool $includeTotal, Response $response, Database $dbForPlatform) {
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
@@ -1548,7 +1550,7 @@ App::get('/v1/projects/:projectId/keys')
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'keys' => $keys,
|
||||
'total' => count($keys),
|
||||
'total' => $includeTotal ? count($keys) : 0,
|
||||
]), Response::MODEL_KEY_LIST);
|
||||
});
|
||||
|
||||
@@ -1834,9 +1836,10 @@ App::get('/v1/projects/:projectId/platforms')
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, Response $response, Database $dbForPlatform) {
|
||||
->action(function (string $projectId, bool $includeTotal, Response $response, Database $dbForPlatform) {
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
@@ -1851,7 +1854,7 @@ App::get('/v1/projects/:projectId/platforms')
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'platforms' => $platforms,
|
||||
'total' => count($platforms),
|
||||
'total' => $includeTotal ? count($platforms) : 0,
|
||||
]), Response::MODEL_PLATFORM_LIST);
|
||||
});
|
||||
|
||||
|
||||
@@ -180,9 +180,10 @@ App::get('/v1/storage/buckets')
|
||||
))
|
||||
->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Buckets::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject) {
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
@@ -222,7 +223,7 @@ App::get('/v1/storage/buckets')
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
try {
|
||||
$buckets = $dbForProject->find('buckets', $queries);
|
||||
$total = $dbForProject->count('buckets', $filterQueries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('buckets', $filterQueries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
} catch (QueryException $e) {
|
||||
@@ -785,10 +786,11 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).')
|
||||
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) {
|
||||
->action(function (string $bucketId, array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject, string $mode) {
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
@@ -846,10 +848,10 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
try {
|
||||
if ($fileSecurity && !$valid) {
|
||||
$files = $dbForProject->find('bucket_' . $bucket->getSequence(), $queries);
|
||||
$total = $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT) : 0;
|
||||
} else {
|
||||
$files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getSequence(), $queries));
|
||||
$total = Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT));
|
||||
$total = $includeTotal ? Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT)) : 0;
|
||||
}
|
||||
} catch (NotFoundException) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
|
||||
@@ -52,6 +52,7 @@ use Utopia\Locale\Locale;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
@@ -169,9 +170,10 @@ App::get('/v1/teams')
|
||||
))
|
||||
->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject) {
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
@@ -211,7 +213,7 @@ App::get('/v1/teams')
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
try {
|
||||
$results = $dbForProject->find('teams', $queries);
|
||||
$total = $dbForProject->count('teams', $filterQueries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('teams', $filterQueries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
@@ -838,10 +840,11 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, array $queries, string $search, Response $response, Document $project, Database $dbForProject) {
|
||||
->action(function (string $teamId, array $queries, string $search, bool $includeTotal, Response $response, Document $project, Database $dbForProject) {
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -893,11 +896,11 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
collection: 'memberships',
|
||||
queries: $queries,
|
||||
);
|
||||
$total = $dbForProject->count(
|
||||
$total = $includeTotal ? $dbForProject->count(
|
||||
collection: 'memberships',
|
||||
queries: $filterQueries,
|
||||
max: APP_LIMIT_COUNT
|
||||
);
|
||||
) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
@@ -1430,11 +1433,12 @@ App::get('/v1/teams/:teamId/logs')
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $teamId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->action(function (string $teamId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
@@ -1503,7 +1507,7 @@ App::get('/v1/teams/:teamId/logs')
|
||||
}
|
||||
}
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByResource($resource, $queries),
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
||||
@@ -605,9 +605,10 @@ App::get('/v1/users')
|
||||
))
|
||||
->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject) {
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
@@ -647,10 +648,10 @@ App::get('/v1/users')
|
||||
$users = [];
|
||||
$total = 0;
|
||||
|
||||
$dbForProject->skipFilters(function () use ($dbForProject, $queries, &$users, &$total) {
|
||||
$dbForProject->skipFilters(function () use ($dbForProject, $queries, $includeTotal, &$users, &$total) {
|
||||
try {
|
||||
$users = $dbForProject->find('users', $queries);
|
||||
$total = $dbForProject->count('users', $queries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('users', $queries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
} catch (QueryException $e) {
|
||||
@@ -784,10 +785,11 @@ App::get('/v1/users/:userId/sessions')
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Locale $locale) {
|
||||
->action(function (string $userId, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
@@ -809,7 +811,7 @@ App::get('/v1/users/:userId/sessions')
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'sessions' => $sessions,
|
||||
'total' => count($sessions),
|
||||
'total' => $includeTotal ? count($sessions) : 0,
|
||||
]), Response::MODEL_SESSION_LIST);
|
||||
});
|
||||
|
||||
@@ -833,9 +835,10 @@ App::get('/v1/users/:userId/memberships')
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
->action(function (string $userId, array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
@@ -869,7 +872,7 @@ App::get('/v1/users/:userId/memberships')
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'memberships' => $memberships,
|
||||
'total' => count($memberships),
|
||||
'total' => $includeTotal ? count($memberships) : 0,
|
||||
]), Response::MODEL_MEMBERSHIP_LIST);
|
||||
});
|
||||
|
||||
@@ -892,11 +895,12 @@ App::get('/v1/users/:userId/logs')
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $userId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->action(function (string $userId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
@@ -965,7 +969,7 @@ App::get('/v1/users/:userId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByUser($user->getSequence(), $queries),
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence(), $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -989,9 +993,10 @@ App::get('/v1/users/:userId/targets')
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('queries', [], new Targets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Targets::ALLOWED_ATTRIBUTES), true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, array $queries, Response $response, Database $dbForProject) {
|
||||
->action(function (string $userId, array $queries, bool $includeTotal, Response $response, Database $dbForProject) {
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1031,7 +1036,7 @@ App::get('/v1/users/:userId/targets')
|
||||
}
|
||||
try {
|
||||
$targets = $dbForProject->find('targets', $queries);
|
||||
$total = $dbForProject->count('targets', $queries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('targets', $queries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
@@ -1060,9 +1065,10 @@ App::get('/v1/users/identities')
|
||||
))
|
||||
->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Identities::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject) {
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
@@ -1099,10 +1105,9 @@ App::get('/v1/users/identities')
|
||||
$cursor->setValue($cursorDocument);
|
||||
}
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
try {
|
||||
$identities = $dbForProject->find('identities', $queries);
|
||||
$total = $dbForProject->count('identities', $filterQueries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForProject->count('identities', $queries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
|
||||
+98
-20
@@ -29,12 +29,20 @@ use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Detector\Detection\Framework\Analog;
|
||||
use Utopia\Detector\Detection\Framework\Angular;
|
||||
use Utopia\Detector\Detection\Framework\Astro;
|
||||
use Utopia\Detector\Detection\Framework\Flutter;
|
||||
use Utopia\Detector\Detection\Framework\Lynx;
|
||||
use Utopia\Detector\Detection\Framework\NextJs;
|
||||
use Utopia\Detector\Detection\Framework\Nuxt;
|
||||
use Utopia\Detector\Detection\Framework\React;
|
||||
use Utopia\Detector\Detection\Framework\ReactNative;
|
||||
use Utopia\Detector\Detection\Framework\Remix;
|
||||
use Utopia\Detector\Detection\Framework\Svelte;
|
||||
use Utopia\Detector\Detection\Framework\SvelteKit;
|
||||
use Utopia\Detector\Detection\Framework\TanStackStart;
|
||||
use Utopia\Detector\Detection\Framework\Vue;
|
||||
use Utopia\Detector\Detection\Packager\NPM;
|
||||
use Utopia\Detector\Detection\Packager\PNPM;
|
||||
use Utopia\Detector\Detection\Packager\Yarn;
|
||||
@@ -58,6 +66,7 @@ use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\VCS\Adapter\Git\GitHub;
|
||||
use Utopia\VCS\Exception\FileNotFound;
|
||||
use Utopia\VCS\Exception\RepositoryNotFound;
|
||||
|
||||
use function Swoole\Coroutine\batch;
|
||||
@@ -166,7 +175,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
|
||||
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
|
||||
} finally {
|
||||
$dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId);
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -237,7 +246,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
|
||||
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
|
||||
} finally {
|
||||
$dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId);
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -458,7 +467,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
$github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment());
|
||||
}
|
||||
} finally {
|
||||
$dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId);
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -818,7 +827,10 @@ App::post('/v1/vcs/github/installations/:installationId/detections')
|
||||
$files = \array_column($files, 'name');
|
||||
$languages = $github->listRepositoryLanguages($owner, $repositoryName);
|
||||
|
||||
$detector = new Packager($files);
|
||||
$detector = new Packager();
|
||||
foreach ($files as $file) {
|
||||
$detector->addInput($file);
|
||||
}
|
||||
$detector
|
||||
->addOption(new Yarn())
|
||||
->addOption(new PNPM())
|
||||
@@ -828,6 +840,14 @@ App::post('/v1/vcs/github/installations/:installationId/detections')
|
||||
$packager = !\is_null($detection) ? $detection->getName() : 'npm';
|
||||
|
||||
if ($type === 'framework') {
|
||||
$packages = '';
|
||||
try {
|
||||
$contentResponse = $github->getRepositoryContent($owner, $repositoryName, \rtrim($providerRootDirectory, '/') . '/package.json');
|
||||
$packages = $contentResponse['content'] ?? '';
|
||||
} catch (FileNotFound $e) {
|
||||
// Continue detection without package.json
|
||||
}
|
||||
|
||||
$output = new Document([
|
||||
'framework' => '',
|
||||
'installCommand' => '',
|
||||
@@ -835,14 +855,27 @@ App::post('/v1/vcs/github/installations/:installationId/detections')
|
||||
'outputDirectory' => '',
|
||||
]);
|
||||
|
||||
$detector = new Framework($files, $packager);
|
||||
$detector = new Framework($packager);
|
||||
$detector->addInput($packages, Framework::INPUT_PACKAGES);
|
||||
foreach ($files as $file) {
|
||||
$detector->addInput($file, Framework::INPUT_FILE);
|
||||
}
|
||||
|
||||
$detector
|
||||
->addOption(new Flutter())
|
||||
->addOption(new Nuxt())
|
||||
->addOption(new Analog())
|
||||
->addOption(new Angular())
|
||||
->addOption(new Astro())
|
||||
->addOption(new SvelteKit())
|
||||
->addOption(new Flutter())
|
||||
->addOption(new Lynx())
|
||||
->addOption(new NextJs())
|
||||
->addOption(new Remix());
|
||||
->addOption(new Nuxt())
|
||||
->addOption(new React())
|
||||
->addOption(new ReactNative())
|
||||
->addOption(new Remix())
|
||||
->addOption(new Svelte())
|
||||
->addOption(new SvelteKit())
|
||||
->addOption(new TanStackStart())
|
||||
->addOption(new Vue());
|
||||
|
||||
$framework = $detector->detect();
|
||||
|
||||
@@ -877,7 +910,18 @@ App::post('/v1/vcs/github/installations/:installationId/detections')
|
||||
];
|
||||
|
||||
foreach ($strategies as $strategy) {
|
||||
$detector = new Runtime($strategy === Strategy::LANGUAGES ? $languages : $files, $strategy, $packager);
|
||||
$detector = new Runtime($strategy, $packager);
|
||||
|
||||
if ($strategy === Strategy::LANGUAGES) {
|
||||
foreach ($languages as $language) {
|
||||
$detector->addInput($language);
|
||||
}
|
||||
} else {
|
||||
foreach ($files as $file) {
|
||||
$detector->addInput($file);
|
||||
}
|
||||
}
|
||||
|
||||
$detector
|
||||
->addOption(new Node())
|
||||
->addOption(new Bun())
|
||||
@@ -984,7 +1028,10 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
|
||||
$files = $github->listRepositoryContents($repo['organization'], $repo['name'], '');
|
||||
$files = \array_column($files, 'name');
|
||||
|
||||
$detector = new Packager($files);
|
||||
$detector = new Packager();
|
||||
foreach ($files as $file) {
|
||||
$detector->addInput($file);
|
||||
}
|
||||
$detector
|
||||
->addOption(new Yarn())
|
||||
->addOption(new PNPM())
|
||||
@@ -994,14 +1041,35 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
|
||||
$packager = !\is_null($detection) ? $detection->getName() : 'npm';
|
||||
|
||||
if ($type === 'framework') {
|
||||
$frameworkDetector = new Framework($files, $packager);
|
||||
$packages = '';
|
||||
try {
|
||||
$contentResponse = $github->getRepositoryContent($repo['organization'], $repo['name'], 'package.json');
|
||||
$packages = $contentResponse['content'] ?? '';
|
||||
} catch (FileNotFound $e) {
|
||||
// Continue detection without package.json
|
||||
}
|
||||
|
||||
$frameworkDetector = new Framework($packager);
|
||||
$frameworkDetector->addInput($packages, Framework::INPUT_PACKAGES);
|
||||
foreach ($files as $file) {
|
||||
$frameworkDetector->addInput($file, Framework::INPUT_FILE);
|
||||
}
|
||||
|
||||
$frameworkDetector
|
||||
->addOption(new Flutter())
|
||||
->addOption(new Nuxt())
|
||||
->addOption(new Analog())
|
||||
->addOption(new Angular())
|
||||
->addOption(new Astro())
|
||||
->addOption(new SvelteKit())
|
||||
->addOption(new Flutter())
|
||||
->addOption(new Lynx())
|
||||
->addOption(new NextJs())
|
||||
->addOption(new Remix());
|
||||
->addOption(new Nuxt())
|
||||
->addOption(new React())
|
||||
->addOption(new ReactNative())
|
||||
->addOption(new Remix())
|
||||
->addOption(new Svelte())
|
||||
->addOption(new SvelteKit())
|
||||
->addOption(new TanStackStart())
|
||||
->addOption(new Vue());
|
||||
|
||||
$detectedFramework = $frameworkDetector->detect();
|
||||
|
||||
@@ -1026,7 +1094,16 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
|
||||
];
|
||||
|
||||
foreach ($strategies as $strategy) {
|
||||
$detector = new Runtime($strategy === Strategy::LANGUAGES ? $languages : $files, $strategy, $packager);
|
||||
$detector = new Runtime($strategy, $packager);
|
||||
if ($strategy === Strategy::LANGUAGES) {
|
||||
foreach ($languages as $language) {
|
||||
$detector->addInput($language);
|
||||
}
|
||||
} else {
|
||||
foreach ($files as $file) {
|
||||
$detector->addInput($file);
|
||||
}
|
||||
}
|
||||
$detector
|
||||
->addOption(new Node())
|
||||
->addOption(new Bun())
|
||||
@@ -1374,7 +1451,7 @@ App::post('/v1/vcs/github/events')
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('repositories', $repository->getId()));
|
||||
}
|
||||
|
||||
$dbForPlatform->deleteDocument('installations', $installation->getId());
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('installations', $installation->getId()));
|
||||
}
|
||||
}
|
||||
} elseif ($event == $github::EVENT_PULL_REQUEST) {
|
||||
@@ -1458,11 +1535,12 @@ App::get('/v1/vcs/installations')
|
||||
))
|
||||
->param('queries', [], new Installations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Installations::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (array $queries, string $search, Response $response, Document $project, Database $dbForProject, Database $dbForPlatform) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Response $response, Document $project, Database $dbForProject, Database $dbForPlatform) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -1503,7 +1581,7 @@ App::get('/v1/vcs/installations')
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
try {
|
||||
$results = $dbForPlatform->find('installations', $queries);
|
||||
$total = $dbForPlatform->count('installations', $filterQueries, APP_LIMIT_COUNT);
|
||||
$total = $includeTotal ? $dbForPlatform->count('installations', $filterQueries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
|
||||
@@ -54,7 +54,20 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar
|
||||
};
|
||||
|
||||
if (array_key_exists($replace, $params)) {
|
||||
$label = \str_replace($find, $params[$replace], $label);
|
||||
$replacement = $params[$replace];
|
||||
// Convert to string if it's not already a string
|
||||
if (!is_string($replacement)) {
|
||||
if (is_array($replacement)) {
|
||||
$replacement = json_encode($replacement);
|
||||
} elseif (is_object($replacement) && method_exists($replacement, '__toString')) {
|
||||
$replacement = (string)$replacement;
|
||||
} elseif (is_scalar($replacement)) {
|
||||
$replacement = (string)$replacement;
|
||||
} else {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "The server encountered an error while parsing the label: $label. Please create an issue on GitHub to allow us to investigate further https://github.com/appwrite/appwrite/issues/new/choose");
|
||||
}
|
||||
}
|
||||
$label = \str_replace($find, $replacement, $label);
|
||||
}
|
||||
}
|
||||
return $label;
|
||||
@@ -580,6 +593,10 @@ App::init()
|
||||
$data = $cache->load($key, $timestamp);
|
||||
|
||||
if (!empty($data) && !$cacheLog->isEmpty()) {
|
||||
$usageMetric = $route->getLabel('usage.metric', null);
|
||||
if ($usageMetric === METRIC_AVATARS_SCREENSHOTS_GENERATED) {
|
||||
$queueForStatsUsage->disableMetric(METRIC_AVATARS_SCREENSHOTS_GENERATED);
|
||||
}
|
||||
$parts = explode('/', $cacheLog->getAttribute('resourceType', ''));
|
||||
$type = $parts[0] ?? null;
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ const APP_PLATFORM_CLIENT = 'client';
|
||||
const APP_PLATFORM_CONSOLE = 'console';
|
||||
const APP_VCS_GITHUB_USERNAME = 'Appwrite';
|
||||
const APP_VCS_GITHUB_EMAIL = 'team@appwrite.io';
|
||||
const APP_VCS_GITHUB_URL = 'https://github.com/TeamAppwrite';
|
||||
const APP_BRANDED_EMAIL_BASE_TEMPLATE = 'email-base-styled';
|
||||
|
||||
// Database Reconnect
|
||||
@@ -269,6 +270,9 @@ const METRIC_SITES_OUTBOUND = 'sites.outbound';
|
||||
const METRIC_SITES_ID_REQUESTS = 'sites.{siteInternalId}.requests';
|
||||
const METRIC_SITES_ID_INBOUND = 'sites.{siteInternalId}.inbound';
|
||||
const METRIC_SITES_ID_OUTBOUND = 'sites.{siteInternalId}.outbound';
|
||||
const METRIC_AVATARS_SCREENSHOTS_GENERATED = 'avatars.screenshotsGenerated';
|
||||
const METRIC_FUNCTIONS_RUNTIME = 'functions.runtimes.{runtime}';
|
||||
const METRIC_SITES_FRAMEWORK = 'sites.frameworks.{framework}';
|
||||
|
||||
// Resource types
|
||||
const RESOURCE_TYPE_PROJECTS = 'projects';
|
||||
|
||||
@@ -555,7 +555,7 @@ App::setResource('deviceForFiles', function ($project, Telemetry $telemetry) {
|
||||
App::setResource('deviceForSites', function ($project, Telemetry $telemetry) {
|
||||
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_SITES . '/app-' . $project->getId()));
|
||||
}, ['project', 'telemetry']);
|
||||
App::setResource('deviceForImports', function ($project, Telemetry $telemetry) {
|
||||
App::setResource('deviceForMigrations', function ($project, Telemetry $telemetry) {
|
||||
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId()));
|
||||
}, ['project', 'telemetry']);
|
||||
App::setResource('deviceForFunctions', function ($project, Telemetry $telemetry) {
|
||||
|
||||
@@ -859,7 +859,7 @@ $image = $this->getParam('image', '');
|
||||
- _APP_ASSISTANT_OPENAI_API_KEY
|
||||
|
||||
appwrite-browser:
|
||||
image: appwrite/browser:0.2.4
|
||||
image: appwrite/browser:0.3.1
|
||||
container_name: appwrite-browser
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
|
||||
+1
-1
@@ -349,7 +349,7 @@ Server::setResource('deviceForSites', function (Document $project, Telemetry $te
|
||||
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_SITES . '/app-' . $project->getId()));
|
||||
}, ['project', 'telemetry']);
|
||||
|
||||
Server::setResource('deviceForImports', function (Document $project, Telemetry $telemetry) {
|
||||
Server::setResource('deviceForMigrations', function (Document $project, Telemetry $telemetry) {
|
||||
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId()));
|
||||
}, ['project', 'telemetry']);
|
||||
|
||||
|
||||
+7
-7
@@ -1,5 +1,4 @@
|
||||
{
|
||||
|
||||
"name": "appwrite/server-ce",
|
||||
"description": "End to end backend server for frontend and mobile apps.",
|
||||
"type": "project",
|
||||
@@ -52,17 +51,18 @@
|
||||
"utopia-php/cache": "0.13.*",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "2.*",
|
||||
"utopia-php/detector": "0.1.*",
|
||||
"utopia-php/domains": "0.8.*",
|
||||
"utopia-php/dns": "0.3.*",
|
||||
"utopia-php/database": "3.*",
|
||||
"utopia-php/detector": "0.2.*",
|
||||
"utopia-php/domains": "0.9.*",
|
||||
"utopia-php/emails": "0.6.*",
|
||||
"utopia-php/dns": "1.1.*",
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/fetch": "0.4.*",
|
||||
"utopia-php/image": "0.8.*",
|
||||
"utopia-php/locale": "0.8.*",
|
||||
"utopia-php/logger": "0.6.*",
|
||||
"utopia-php/messaging": "0.19.*",
|
||||
"utopia-php/messaging": "0.20.*",
|
||||
"utopia-php/migration": "1.*",
|
||||
"utopia-php/orchestration": "0.9.*",
|
||||
"utopia-php/platform": "0.7.*",
|
||||
@@ -74,7 +74,7 @@
|
||||
"utopia-php/swoole": "0.8.*",
|
||||
"utopia-php/system": "0.9.*",
|
||||
"utopia-php/telemetry": "0.1.*",
|
||||
"utopia-php/vcs": "0.11.*",
|
||||
"utopia-php/vcs": "0.12.*",
|
||||
"utopia-php/websocket": "0.3.*",
|
||||
"matomo/device-detector": "6.4.*",
|
||||
"dragonmantank/cron-expression": "3.4.*",
|
||||
|
||||
Generated
+465
-90
@@ -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": "568800edca746c4e8d0d50648b25f589",
|
||||
"content-hash": "ad28b7155175986191bd19bbcd13d623",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -161,16 +161,16 @@
|
||||
},
|
||||
{
|
||||
"name": "appwrite/php-runtimes",
|
||||
"version": "0.19.2",
|
||||
"version": "0.19.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/runtimes.git",
|
||||
"reference": "e5c142519df5aced37de9c302971c29c079ce3d9"
|
||||
"reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/runtimes/zipball/e5c142519df5aced37de9c302971c29c079ce3d9",
|
||||
"reference": "e5c142519df5aced37de9c302971c29c079ce3d9",
|
||||
"url": "https://api.github.com/repos/appwrite/runtimes/zipball/7bd0cc3cb97de625d7b07230bd91b121f88e72ae",
|
||||
"reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -210,9 +210,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/runtimes/issues",
|
||||
"source": "https://github.com/appwrite/runtimes/tree/0.19.2"
|
||||
"source": "https://github.com/appwrite/runtimes/tree/0.19.1"
|
||||
},
|
||||
"time": "2025-11-11T13:44:44+00:00"
|
||||
"time": "2025-05-27T07:12:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "beberlei/assert",
|
||||
@@ -756,16 +756,16 @@
|
||||
},
|
||||
{
|
||||
"name": "google/protobuf",
|
||||
"version": "v4.33.1",
|
||||
"version": "v4.33.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/protocolbuffers/protobuf-php.git",
|
||||
"reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12"
|
||||
"reference": "b50269e23204e5ae859a326ec3d90f09efe3047d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/0cd73ccf0cd26c3e72299cce1ea6144091a57e12",
|
||||
"reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12",
|
||||
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/b50269e23204e5ae859a326ec3d90f09efe3047d",
|
||||
"reference": "b50269e23204e5ae859a326ec3d90f09efe3047d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -794,9 +794,9 @@
|
||||
"proto"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.1"
|
||||
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.0"
|
||||
},
|
||||
"time": "2025-11-12T21:58:05+00:00"
|
||||
"time": "2025-10-15T20:10:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/csv",
|
||||
@@ -959,6 +959,83 @@
|
||||
},
|
||||
"time": "2025-08-20T17:20:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mongodb/mongodb",
|
||||
"version": "2.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mongodb/mongo-php-library.git",
|
||||
"reference": "f399d24905dd42f97dfe0af9706129743ef247ac"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/f399d24905dd42f97dfe0af9706129743ef247ac",
|
||||
"reference": "f399d24905dd42f97dfe0af9706129743ef247ac",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-runtime-api": "^2.0",
|
||||
"ext-mongodb": "^2.1",
|
||||
"php": "^8.1",
|
||||
"psr/log": "^1.1.4|^2|^3",
|
||||
"symfony/polyfill-php85": "^1.32"
|
||||
},
|
||||
"replace": {
|
||||
"mongodb/builder": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^12.0",
|
||||
"phpunit/phpunit": "^10.5.35",
|
||||
"rector/rector": "^1.2",
|
||||
"squizlabs/php_codesniffer": "^3.7",
|
||||
"vimeo/psalm": "6.5.*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"MongoDB\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Andreas Braun",
|
||||
"email": "andreas.braun@mongodb.com"
|
||||
},
|
||||
{
|
||||
"name": "Jeremy Mikola",
|
||||
"email": "jmikola@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jérôme Tamarelle",
|
||||
"email": "jerome.tamarelle@mongodb.com"
|
||||
}
|
||||
],
|
||||
"description": "MongoDB driver library",
|
||||
"homepage": "https://jira.mongodb.org/browse/PHPLIB",
|
||||
"keywords": [
|
||||
"database",
|
||||
"driver",
|
||||
"mongodb",
|
||||
"persistence"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mongodb/mongo-php-library/issues",
|
||||
"source": "https://github.com/mongodb/mongo-php-library/tree/2.1.1"
|
||||
},
|
||||
"time": "2025-08-13T20:50:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mustangostang/spyc",
|
||||
"version": "0.6.3",
|
||||
@@ -3017,6 +3094,86 @@
|
||||
],
|
||||
"time": "2025-07-08T02:45:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php85",
|
||||
"version": "v1.33.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php85.git",
|
||||
"reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
|
||||
"reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php85\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-23T16:12:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
"version": "v3.6.1",
|
||||
@@ -3638,30 +3795,80 @@
|
||||
"time": "2020-10-24T09:49:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "2.3.2",
|
||||
"name": "utopia-php/console",
|
||||
"version": "0.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "35c978ddd20b649d119296094686d3cc9fcf161f"
|
||||
"url": "https://github.com/utopia-php/console.git",
|
||||
"reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/35c978ddd20b649d119296094686d3cc9fcf161f",
|
||||
"reference": "35c978ddd20b649d119296094686d3cc9fcf161f",
|
||||
"url": "https://api.github.com/repos/utopia-php/console/zipball/f77104e4a888fa9cb3e08f32955ec09479ab7a92",
|
||||
"reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.2.*",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"squizlabs/php_codesniffer": "^3.6",
|
||||
"swoole/ide-helper": "4.8.8"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Utopia\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Console helpers for logging, prompting, and executing commands",
|
||||
"keywords": [
|
||||
"cli",
|
||||
"console",
|
||||
"php",
|
||||
"terminal",
|
||||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/console/issues",
|
||||
"source": "https://github.com/utopia-php/console/tree/0.0.1"
|
||||
},
|
||||
"time": "2025-10-20T14:41:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "f2d01b6b38057891184f62107bf70a55bc2ea068"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/f2d01b6b38057891184f62107bf70a55bc2ea068",
|
||||
"reference": "f2d01b6b38057891184f62107bf70a55bc2ea068",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"ext-mongodb": "*",
|
||||
"ext-pdo": "*",
|
||||
"php": ">=8.1",
|
||||
"utopia-php/cache": "0.13.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/mongo": "0.11.*",
|
||||
"utopia-php/pools": "0.8.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "1.23.*",
|
||||
"laravel/pint": "1.*",
|
||||
"laravel/pint": "*",
|
||||
"pcov/clobber": "2.*",
|
||||
"phpstan/phpstan": "1.*",
|
||||
"phpunit/phpunit": "9.*",
|
||||
@@ -3689,22 +3896,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/2.3.2"
|
||||
"source": "https://github.com/utopia-php/database/tree/3.2.0"
|
||||
},
|
||||
"time": "2025-10-07T03:09:32+00:00"
|
||||
"time": "2025-11-06T05:41:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
"version": "0.1.5",
|
||||
"version": "0.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/detector.git",
|
||||
"reference": "b5d6ba51352485b524589bc0ee8d07a9efafe718"
|
||||
"reference": "9a41be5f21efe2d865de79b08dff94fff85ce5e9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/detector/zipball/b5d6ba51352485b524589bc0ee8d07a9efafe718",
|
||||
"reference": "b5d6ba51352485b524589bc0ee8d07a9efafe718",
|
||||
"url": "https://api.github.com/repos/utopia-php/detector/zipball/9a41be5f21efe2d865de79b08dff94fff85ce5e9",
|
||||
"reference": "9a41be5f21efe2d865de79b08dff94fff85ce5e9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3734,35 +3941,36 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/detector/issues",
|
||||
"source": "https://github.com/utopia-php/detector/tree/0.1.5"
|
||||
"source": "https://github.com/utopia-php/detector/tree/0.2.2"
|
||||
},
|
||||
"time": "2025-05-19T11:01:28+00:00"
|
||||
"time": "2025-10-31T12:43:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/dns",
|
||||
"version": "0.3.0",
|
||||
"version": "1.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/dns.git",
|
||||
"reference": "8fd4161bc3a8021a670c1101b40f6b09a97f1a54"
|
||||
"reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/dns/zipball/8fd4161bc3a8021a670c1101b40f6b09a97f1a54",
|
||||
"reference": "8fd4161bc3a8021a670c1101b40f6b09a97f1a54",
|
||||
"url": "https://api.github.com/repos/utopia-php/dns/zipball/1e6b4bac735329c9e5ec69a6a5d899ec2d050707",
|
||||
"reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/telemetry": "^0.1.1"
|
||||
"php": ">=8.3",
|
||||
"utopia-php/console": "0.0.*",
|
||||
"utopia-php/domains": "0.9.*",
|
||||
"utopia-php/telemetry": "0.1.*",
|
||||
"utopia-php/validators": "^0.0.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.2.*",
|
||||
"phpstan/phpstan": "1.8.*",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"rregeer/phpunit-coverage-check": "^0.3.1",
|
||||
"swoole/ide-helper": "4.6.6"
|
||||
"laravel/pint": "1.25.*",
|
||||
"phpstan/phpstan": "2.0.*",
|
||||
"phpunit/phpunit": "12.4.*",
|
||||
"swoole/ide-helper": "5.1.8"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -3790,27 +3998,28 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/dns/issues",
|
||||
"source": "https://github.com/utopia-php/dns/tree/0.3.0"
|
||||
"source": "https://github.com/utopia-php/dns/tree/1.1.3"
|
||||
},
|
||||
"time": "2025-08-04T11:05:53+00:00"
|
||||
"time": "2025-11-06T19:08:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
"version": "0.8.4",
|
||||
"version": "0.9.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/domains.git",
|
||||
"reference": "316a76b0fcbc7f82e40be466c22c19acb243ee22"
|
||||
"reference": "99b4ec95d5d6b7a5c990a66c56412212d9af37e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/domains/zipball/316a76b0fcbc7f82e40be466c22c19acb243ee22",
|
||||
"reference": "316a76b0fcbc7f82e40be466c22c19acb243ee22",
|
||||
"url": "https://api.github.com/repos/utopia-php/domains/zipball/99b4ec95d5d6b7a5c990a66c56412212d9af37e7",
|
||||
"reference": "99b4ec95d5d6b7a5c990a66c56412212d9af37e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/framework": "0.33.*"
|
||||
"utopia-php/cache": "0.13.*",
|
||||
"utopia-php/validators": "0.0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.2.*",
|
||||
@@ -3851,9 +4060,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/domains/issues",
|
||||
"source": "https://github.com/utopia-php/domains/tree/0.8.4"
|
||||
"source": "https://github.com/utopia-php/domains/tree/0.9.1"
|
||||
},
|
||||
"time": "2025-10-17T11:31:56+00:00"
|
||||
"time": "2025-10-21T14:52:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/dsn",
|
||||
@@ -3902,6 +4111,66 @@
|
||||
},
|
||||
"time": "2024-05-07T02:01:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/emails",
|
||||
"version": "0.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/emails.git",
|
||||
"reference": "9c4c40cf7c03c2e9e21364566f9b192d03ea93c9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/emails/zipball/9c4c40cf7c03c2e9e21364566f9b192d03ea93c9",
|
||||
"reference": "9c4c40cf7c03c2e9e21364566f9b192d03ea93c9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cli": "^0.15",
|
||||
"utopia-php/domains": "^0.9",
|
||||
"utopia-php/fetch": "^0.4",
|
||||
"utopia-php/validators": "^0.0.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.25.*",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Utopia\\Emails\\": "src/Emails"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eldad Fux",
|
||||
"email": "eldad@appwrite.io"
|
||||
}
|
||||
],
|
||||
"description": "Utopia Emails library is simple and lite library for parsing and validating email addresses. This library is aiming to be as simple and easy to learn and use.",
|
||||
"keywords": [
|
||||
"RFC5322",
|
||||
"email",
|
||||
"emails",
|
||||
"framework",
|
||||
"parsing",
|
||||
"php",
|
||||
"upf",
|
||||
"utopia",
|
||||
"validation"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/emails/issues",
|
||||
"source": "https://github.com/utopia-php/emails/tree/0.6.2"
|
||||
},
|
||||
"time": "2025-10-28T16:08:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/fetch",
|
||||
"version": "0.4.2",
|
||||
@@ -3943,16 +4212,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/framework",
|
||||
"version": "0.33.29",
|
||||
"version": "0.33.28",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/http.git",
|
||||
"reference": "6e63939fdb33b847f92839499cd6e8df626c278d"
|
||||
"reference": "5aaa94d406577b0059ad28c78022606890dc6de0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/6e63939fdb33b847f92839499cd6e8df626c278d",
|
||||
"reference": "6e63939fdb33b847f92839499cd6e8df626c278d",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/5aaa94d406577b0059ad28c78022606890dc6de0",
|
||||
"reference": "5aaa94d406577b0059ad28c78022606890dc6de0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3984,9 +4253,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/http/issues",
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.29"
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.28"
|
||||
},
|
||||
"time": "2025-11-14T06:33:29+00:00"
|
||||
"time": "2025-09-25T10:44:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
@@ -4140,16 +4409,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/messaging",
|
||||
"version": "0.19.0",
|
||||
"version": "0.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/messaging.git",
|
||||
"reference": "0b866d54e70c792a3c4f5ca9c12a6d358a31f4b8"
|
||||
"reference": "6c5be4588d97e3732a1907ecb13cd8a098eade96"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/0b866d54e70c792a3c4f5ca9c12a6d358a31f4b8",
|
||||
"reference": "0b866d54e70c792a3c4f5ca9c12a6d358a31f4b8",
|
||||
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/6c5be4588d97e3732a1907ecb13cd8a098eade96",
|
||||
"reference": "6c5be4588d97e3732a1907ecb13cd8a098eade96",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4185,22 +4454,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/messaging/issues",
|
||||
"source": "https://github.com/utopia-php/messaging/tree/0.19.0"
|
||||
"source": "https://github.com/utopia-php/messaging/tree/0.20.0"
|
||||
},
|
||||
"time": "2025-10-14T11:46:49+00:00"
|
||||
"time": "2025-10-22T04:27:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "1.1.0",
|
||||
"version": "1.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "6fb6f8f032cd34c3c65728a55d494adeac2ff038"
|
||||
"reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/6fb6f8f032cd34c3c65728a55d494adeac2ff038",
|
||||
"reference": "6fb6f8f032cd34c3c65728a55d494adeac2ff038",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/731b3a963c58c30e0b2368695d57a7e8fcb7455c",
|
||||
"reference": "731b3a963c58c30e0b2368695d57a7e8fcb7455c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4208,9 +4477,9 @@
|
||||
"ext-curl": "*",
|
||||
"ext-openssl": "*",
|
||||
"php": ">=8.1",
|
||||
"utopia-php/database": "2.*",
|
||||
"utopia-php/console": "0.0.*",
|
||||
"utopia-php/database": "3.*",
|
||||
"utopia-php/dsn": "0.2.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/storage": "0.18.*"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -4218,7 +4487,6 @@
|
||||
"laravel/pint": "1.*",
|
||||
"phpstan/phpstan": "1.*",
|
||||
"phpunit/phpunit": "11.*",
|
||||
"utopia-php/cli": "0.16.*",
|
||||
"vlucas/phpdotenv": "5.*"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -4241,9 +4509,70 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.1.0"
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.3.3"
|
||||
},
|
||||
"time": "2025-09-10T05:45:30+00:00"
|
||||
"time": "2025-10-28T04:02:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
"version": "0.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/mongo.git",
|
||||
"reference": "34bc0cda8ea368cde68702a6fffe2c3ac625398e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/34bc0cda8ea368cde68702a6fffe2c3ac625398e",
|
||||
"reference": "34bc0cda8ea368cde68702a6fffe2c3ac625398e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mongodb": "2.1.*",
|
||||
"mongodb/mongodb": "2.1.*",
|
||||
"php": ">=8.0",
|
||||
"ramsey/uuid": "4.9.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "1.*",
|
||||
"laravel/pint": "*",
|
||||
"phpstan/phpstan": "*",
|
||||
"phpunit/phpunit": "9.*",
|
||||
"swoole/ide-helper": "5.1.*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Utopia\\Mongo\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eldad Fux",
|
||||
"email": "eldad@appwrite.io"
|
||||
},
|
||||
{
|
||||
"name": "Wess",
|
||||
"email": "wess@appwrite.io"
|
||||
}
|
||||
],
|
||||
"description": "A simple library to manage Mongo database",
|
||||
"keywords": [
|
||||
"database",
|
||||
"mongo",
|
||||
"php",
|
||||
"upf",
|
||||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/mongo/issues",
|
||||
"source": "https://github.com/utopia-php/mongo/tree/0.11.0"
|
||||
},
|
||||
"time": "2025-10-20T11:11:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/orchestration",
|
||||
@@ -4784,17 +5113,63 @@
|
||||
"time": "2025-03-17T11:57:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
"version": "0.11.0",
|
||||
"name": "utopia-php/validators",
|
||||
"version": "0.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "0e665eaa7d906168525bf6aac50b6bcc3e4fe528"
|
||||
"url": "https://github.com/utopia-php/validators.git",
|
||||
"reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/0e665eaa7d906168525bf6aac50b6bcc3e4fe528",
|
||||
"reference": "0e665eaa7d906168525bf6aac50b6bcc3e4fe528",
|
||||
"url": "https://api.github.com/repos/utopia-php/validators/zipball/894210695c5d35fa248fb65f7fe7237b6ff4fb0b",
|
||||
"reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-xdebug": "*",
|
||||
"laravel/pint": "^1.2",
|
||||
"phpstan/phpstan": "1.*",
|
||||
"phpunit/phpunit": "^9.5.25"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Utopia\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "A lightweight collection of reusable validators for Utopia projects",
|
||||
"keywords": [
|
||||
"php",
|
||||
"utopia",
|
||||
"validation",
|
||||
"validator"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/validators/issues",
|
||||
"source": "https://github.com/utopia-php/validators/tree/0.0.2"
|
||||
},
|
||||
"time": "2025-10-20T21:52:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
"version": "0.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "28457cf347972c4ec95d3ca77776a4921364a665"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/28457cf347972c4ec95d3ca77776a4921364a665",
|
||||
"reference": "28457cf347972c4ec95d3ca77776a4921364a665",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4828,9 +5203,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.11.0"
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.12.0"
|
||||
},
|
||||
"time": "2025-07-23T13:54:58+00:00"
|
||||
"time": "2025-10-22T12:58:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/websocket",
|
||||
@@ -5008,16 +5383,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.5.5",
|
||||
"version": "1.5.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "1f3686e41a2d10829220b74f54c80a770e9f968a"
|
||||
"reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1f3686e41a2d10829220b74f54c80a770e9f968a",
|
||||
"reference": "1f3686e41a2d10829220b74f54c80a770e9f968a",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d",
|
||||
"reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5053,9 +5428,9 @@
|
||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.5.5"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.5.3"
|
||||
},
|
||||
"time": "2025-11-14T05:56:33+00:00"
|
||||
"time": "2025-11-10T09:50:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@@ -8343,16 +8718,16 @@
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.3.0",
|
||||
"version": "1.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb"
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb",
|
||||
"reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8381,7 +8756,7 @@
|
||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"support": {
|
||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.3.0"
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8389,7 +8764,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-13T13:44:09+00:00"
|
||||
"time": "2024-03-03T12:36:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
appwrite:
|
||||
# volumes:
|
||||
# - ~/.ssh:/root/.ssh
|
||||
environment:
|
||||
- GH_TOKEN=
|
||||
- GIT_EMAIL=
|
||||
+4
-3
@@ -219,7 +219,7 @@ services:
|
||||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: appwrite/console:7.4.7
|
||||
image: appwrite/console:7.4.11
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
@@ -698,6 +698,7 @@ services:
|
||||
- appwrite
|
||||
volumes:
|
||||
- appwrite-imports:/storage/imports:rw
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
- ./tests:/usr/src/code/tests
|
||||
@@ -957,7 +958,7 @@ services:
|
||||
|
||||
appwrite-browser:
|
||||
container_name: appwrite-browser
|
||||
image: appwrite/browser:0.2.4
|
||||
image: appwrite/browser:0.3.1
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
@@ -966,7 +967,7 @@ services:
|
||||
hostname: exc1
|
||||
<<: *x-logging
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/executor:0.11.0
|
||||
image: openruntimes/executor:0.11.4
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
@@ -10,6 +10,7 @@ Account account = new Account(client);
|
||||
|
||||
account.listIdentities(
|
||||
listOf(), // queries (optional)
|
||||
false, // total (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -10,6 +10,7 @@ Account account = new Account(client);
|
||||
|
||||
account.listLogs(
|
||||
listOf(), // queries (optional)
|
||||
false, // total (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client;
|
||||
import io.appwrite.coroutines.CoroutineCallback;
|
||||
import io.appwrite.services.Databases;
|
||||
import io.appwrite.Permission;
|
||||
import io.appwrite.Role;
|
||||
|
||||
Client client = new Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -19,7 +21,7 @@ databases.createDocument(
|
||||
"age" to 30,
|
||||
"isAdmin" to false
|
||||
), // data
|
||||
listOf("read("any")"), // permissions (optional)
|
||||
listOf(Permission.read(Role.any())), // permissions (optional)
|
||||
"<TRANSACTION_ID>", // transactionId (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
|
||||
@@ -13,6 +13,7 @@ databases.listDocuments(
|
||||
"<COLLECTION_ID>", // collectionId
|
||||
listOf(), // queries (optional)
|
||||
"<TRANSACTION_ID>", // transactionId (optional)
|
||||
false, // total (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client;
|
||||
import io.appwrite.coroutines.CoroutineCallback;
|
||||
import io.appwrite.services.Databases;
|
||||
import io.appwrite.Permission;
|
||||
import io.appwrite.Role;
|
||||
|
||||
Client client = new Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,7 +15,7 @@ databases.updateDocument(
|
||||
"<COLLECTION_ID>", // collectionId
|
||||
"<DOCUMENT_ID>", // documentId
|
||||
mapOf( "a" to "b" ), // data (optional)
|
||||
listOf("read("any")"), // permissions (optional)
|
||||
listOf(Permission.read(Role.any())), // permissions (optional)
|
||||
"<TRANSACTION_ID>", // transactionId (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client;
|
||||
import io.appwrite.coroutines.CoroutineCallback;
|
||||
import io.appwrite.services.Databases;
|
||||
import io.appwrite.Permission;
|
||||
import io.appwrite.Role;
|
||||
|
||||
Client client = new Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,7 +15,7 @@ databases.upsertDocument(
|
||||
"<COLLECTION_ID>", // collectionId
|
||||
"<DOCUMENT_ID>", // documentId
|
||||
mapOf( "a" to "b" ), // data
|
||||
listOf("read("any")"), // permissions (optional)
|
||||
listOf(Permission.read(Role.any())), // permissions (optional)
|
||||
"<TRANSACTION_ID>", // transactionId (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
|
||||
@@ -11,6 +11,7 @@ Functions functions = new Functions(client);
|
||||
functions.listExecutions(
|
||||
"<FUNCTION_ID>", // functionId
|
||||
listOf(), // queries (optional)
|
||||
false, // total (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -2,6 +2,8 @@ import io.appwrite.Client;
|
||||
import io.appwrite.coroutines.CoroutineCallback;
|
||||
import io.appwrite.models.InputFile;
|
||||
import io.appwrite.services.Storage;
|
||||
import io.appwrite.Permission;
|
||||
import io.appwrite.Role;
|
||||
|
||||
Client client = new Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,7 +15,7 @@ storage.createFile(
|
||||
"<BUCKET_ID>", // bucketId
|
||||
"<FILE_ID>", // fileId
|
||||
InputFile.fromPath("file.png"), // file
|
||||
listOf("read("any")"), // permissions (optional)
|
||||
listOf(Permission.read(Role.any())), // permissions (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -12,6 +12,7 @@ storage.listFiles(
|
||||
"<BUCKET_ID>", // bucketId
|
||||
listOf(), // queries (optional)
|
||||
"<SEARCH>", // search (optional)
|
||||
false, // total (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client;
|
||||
import io.appwrite.coroutines.CoroutineCallback;
|
||||
import io.appwrite.services.Storage;
|
||||
import io.appwrite.Permission;
|
||||
import io.appwrite.Role;
|
||||
|
||||
Client client = new Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -12,7 +14,7 @@ storage.updateFile(
|
||||
"<BUCKET_ID>", // bucketId
|
||||
"<FILE_ID>", // fileId
|
||||
"<NAME>", // name (optional)
|
||||
listOf("read("any")"), // permissions (optional)
|
||||
listOf(Permission.read(Role.any())), // permissions (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client;
|
||||
import io.appwrite.coroutines.CoroutineCallback;
|
||||
import io.appwrite.services.TablesDB;
|
||||
import io.appwrite.Permission;
|
||||
import io.appwrite.Role;
|
||||
|
||||
Client client = new Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -19,7 +21,7 @@ tablesDB.createRow(
|
||||
"age" to 30,
|
||||
"isAdmin" to false
|
||||
), // data
|
||||
listOf("read("any")"), // permissions (optional)
|
||||
listOf(Permission.read(Role.any())), // permissions (optional)
|
||||
"<TRANSACTION_ID>", // transactionId (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
|
||||
@@ -13,6 +13,7 @@ tablesDB.listRows(
|
||||
"<TABLE_ID>", // tableId
|
||||
listOf(), // queries (optional)
|
||||
"<TRANSACTION_ID>", // transactionId (optional)
|
||||
false, // total (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client;
|
||||
import io.appwrite.coroutines.CoroutineCallback;
|
||||
import io.appwrite.services.TablesDB;
|
||||
import io.appwrite.Permission;
|
||||
import io.appwrite.Role;
|
||||
|
||||
Client client = new Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,7 +15,7 @@ tablesDB.updateRow(
|
||||
"<TABLE_ID>", // tableId
|
||||
"<ROW_ID>", // rowId
|
||||
mapOf( "a" to "b" ), // data (optional)
|
||||
listOf("read("any")"), // permissions (optional)
|
||||
listOf(Permission.read(Role.any())), // permissions (optional)
|
||||
"<TRANSACTION_ID>", // transactionId (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client;
|
||||
import io.appwrite.coroutines.CoroutineCallback;
|
||||
import io.appwrite.services.TablesDB;
|
||||
import io.appwrite.Permission;
|
||||
import io.appwrite.Role;
|
||||
|
||||
Client client = new Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,7 +15,7 @@ tablesDB.upsertRow(
|
||||
"<TABLE_ID>", // tableId
|
||||
"<ROW_ID>", // rowId
|
||||
mapOf( "a" to "b" ), // data (optional)
|
||||
listOf("read("any")"), // permissions (optional)
|
||||
listOf(Permission.read(Role.any())), // permissions (optional)
|
||||
"<TRANSACTION_ID>", // transactionId (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
|
||||
@@ -12,6 +12,7 @@ teams.listMemberships(
|
||||
"<TEAM_ID>", // teamId
|
||||
listOf(), // queries (optional)
|
||||
"<SEARCH>", // search (optional)
|
||||
false, // total (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -11,6 +11,7 @@ Teams teams = new Teams(client);
|
||||
teams.list(
|
||||
listOf(), // queries (optional)
|
||||
"<SEARCH>", // search (optional)
|
||||
false, // total (optional)
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
|
||||
@@ -10,4 +10,5 @@ val account = Account(client)
|
||||
|
||||
val result = account.listIdentities(
|
||||
queries = listOf(), // (optional)
|
||||
total = false, // (optional)
|
||||
)
|
||||
@@ -10,4 +10,5 @@ val account = Account(client)
|
||||
|
||||
val result = account.listLogs(
|
||||
queries = listOf(), // (optional)
|
||||
total = false, // (optional)
|
||||
)
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.coroutines.CoroutineCallback
|
||||
import io.appwrite.services.Databases
|
||||
import io.appwrite.Permission
|
||||
import io.appwrite.Role
|
||||
|
||||
val client = Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -19,6 +21,6 @@ val result = databases.createDocument(
|
||||
"age" to 30,
|
||||
"isAdmin" to false
|
||||
),
|
||||
permissions = listOf("read("any")"), // (optional)
|
||||
permissions = listOf(Permission.read(Role.any())), // (optional)
|
||||
transactionId = "<TRANSACTION_ID>", // (optional)
|
||||
)
|
||||
@@ -13,4 +13,5 @@ val result = databases.listDocuments(
|
||||
collectionId = "<COLLECTION_ID>",
|
||||
queries = listOf(), // (optional)
|
||||
transactionId = "<TRANSACTION_ID>", // (optional)
|
||||
total = false, // (optional)
|
||||
)
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.coroutines.CoroutineCallback
|
||||
import io.appwrite.services.Databases
|
||||
import io.appwrite.Permission
|
||||
import io.appwrite.Role
|
||||
|
||||
val client = Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,6 +15,6 @@ val result = databases.updateDocument(
|
||||
collectionId = "<COLLECTION_ID>",
|
||||
documentId = "<DOCUMENT_ID>",
|
||||
data = mapOf( "a" to "b" ), // (optional)
|
||||
permissions = listOf("read("any")"), // (optional)
|
||||
permissions = listOf(Permission.read(Role.any())), // (optional)
|
||||
transactionId = "<TRANSACTION_ID>", // (optional)
|
||||
)
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.coroutines.CoroutineCallback
|
||||
import io.appwrite.services.Databases
|
||||
import io.appwrite.Permission
|
||||
import io.appwrite.Role
|
||||
|
||||
val client = Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,6 +15,6 @@ val result = databases.upsertDocument(
|
||||
collectionId = "<COLLECTION_ID>",
|
||||
documentId = "<DOCUMENT_ID>",
|
||||
data = mapOf( "a" to "b" ),
|
||||
permissions = listOf("read("any")"), // (optional)
|
||||
permissions = listOf(Permission.read(Role.any())), // (optional)
|
||||
transactionId = "<TRANSACTION_ID>", // (optional)
|
||||
)
|
||||
@@ -11,4 +11,5 @@ val functions = Functions(client)
|
||||
val result = functions.listExecutions(
|
||||
functionId = "<FUNCTION_ID>",
|
||||
queries = listOf(), // (optional)
|
||||
total = false, // (optional)
|
||||
)
|
||||
@@ -2,6 +2,8 @@ import io.appwrite.Client
|
||||
import io.appwrite.coroutines.CoroutineCallback
|
||||
import io.appwrite.models.InputFile
|
||||
import io.appwrite.services.Storage
|
||||
import io.appwrite.Permission
|
||||
import io.appwrite.Role
|
||||
|
||||
val client = Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,5 +15,5 @@ val result = storage.createFile(
|
||||
bucketId = "<BUCKET_ID>",
|
||||
fileId = "<FILE_ID>",
|
||||
file = InputFile.fromPath("file.png"),
|
||||
permissions = listOf("read("any")"), // (optional)
|
||||
permissions = listOf(Permission.read(Role.any())), // (optional)
|
||||
)
|
||||
@@ -12,4 +12,5 @@ val result = storage.listFiles(
|
||||
bucketId = "<BUCKET_ID>",
|
||||
queries = listOf(), // (optional)
|
||||
search = "<SEARCH>", // (optional)
|
||||
total = false, // (optional)
|
||||
)
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.coroutines.CoroutineCallback
|
||||
import io.appwrite.services.Storage
|
||||
import io.appwrite.Permission
|
||||
import io.appwrite.Role
|
||||
|
||||
val client = Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -12,5 +14,5 @@ val result = storage.updateFile(
|
||||
bucketId = "<BUCKET_ID>",
|
||||
fileId = "<FILE_ID>",
|
||||
name = "<NAME>", // (optional)
|
||||
permissions = listOf("read("any")"), // (optional)
|
||||
permissions = listOf(Permission.read(Role.any())), // (optional)
|
||||
)
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.coroutines.CoroutineCallback
|
||||
import io.appwrite.services.TablesDB
|
||||
import io.appwrite.Permission
|
||||
import io.appwrite.Role
|
||||
|
||||
val client = Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -19,6 +21,6 @@ val result = tablesDB.createRow(
|
||||
"age" to 30,
|
||||
"isAdmin" to false
|
||||
),
|
||||
permissions = listOf("read("any")"), // (optional)
|
||||
permissions = listOf(Permission.read(Role.any())), // (optional)
|
||||
transactionId = "<TRANSACTION_ID>", // (optional)
|
||||
)
|
||||
@@ -13,4 +13,5 @@ val result = tablesDB.listRows(
|
||||
tableId = "<TABLE_ID>",
|
||||
queries = listOf(), // (optional)
|
||||
transactionId = "<TRANSACTION_ID>", // (optional)
|
||||
total = false, // (optional)
|
||||
)
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.coroutines.CoroutineCallback
|
||||
import io.appwrite.services.TablesDB
|
||||
import io.appwrite.Permission
|
||||
import io.appwrite.Role
|
||||
|
||||
val client = Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,6 +15,6 @@ val result = tablesDB.updateRow(
|
||||
tableId = "<TABLE_ID>",
|
||||
rowId = "<ROW_ID>",
|
||||
data = mapOf( "a" to "b" ), // (optional)
|
||||
permissions = listOf("read("any")"), // (optional)
|
||||
permissions = listOf(Permission.read(Role.any())), // (optional)
|
||||
transactionId = "<TRANSACTION_ID>", // (optional)
|
||||
)
|
||||
@@ -1,6 +1,8 @@
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.coroutines.CoroutineCallback
|
||||
import io.appwrite.services.TablesDB
|
||||
import io.appwrite.Permission
|
||||
import io.appwrite.Role
|
||||
|
||||
val client = Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
@@ -13,6 +15,6 @@ val result = tablesDB.upsertRow(
|
||||
tableId = "<TABLE_ID>",
|
||||
rowId = "<ROW_ID>",
|
||||
data = mapOf( "a" to "b" ), // (optional)
|
||||
permissions = listOf("read("any")"), // (optional)
|
||||
permissions = listOf(Permission.read(Role.any())), // (optional)
|
||||
transactionId = "<TRANSACTION_ID>", // (optional)
|
||||
)
|
||||
@@ -12,4 +12,5 @@ val result = teams.listMemberships(
|
||||
teamId = "<TEAM_ID>",
|
||||
queries = listOf(), // (optional)
|
||||
search = "<SEARCH>", // (optional)
|
||||
total = false, // (optional)
|
||||
)
|
||||
@@ -11,4 +11,5 @@ val teams = Teams(client)
|
||||
val result = teams.list(
|
||||
queries = listOf(), // (optional)
|
||||
search = "<SEARCH>", // (optional)
|
||||
total = false, // (optional)
|
||||
)
|
||||
@@ -7,6 +7,7 @@ let client = Client()
|
||||
let account = Account(client)
|
||||
|
||||
let identityList = try await account.listIdentities(
|
||||
queries: [] // optional
|
||||
queries: [], // optional
|
||||
total: false // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ let client = Client()
|
||||
let account = Account(client)
|
||||
|
||||
let logList = try await account.listLogs(
|
||||
queries: [] // optional
|
||||
queries: [], // optional
|
||||
total: false // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ let document = try await databases.createDocument(
|
||||
"age": 30,
|
||||
"isAdmin": false
|
||||
],
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
transactionId: "<TRANSACTION_ID>" // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ let documentList = try await databases.listDocuments(
|
||||
databaseId: "<DATABASE_ID>",
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
queries: [], // optional
|
||||
transactionId: "<TRANSACTION_ID>" // optional
|
||||
transactionId: "<TRANSACTION_ID>", // optional
|
||||
total: false // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ let document = try await databases.updateDocument(
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
documentId: "<DOCUMENT_ID>",
|
||||
data: [:], // optional
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
transactionId: "<TRANSACTION_ID>" // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ let document = try await databases.upsertDocument(
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
documentId: "<DOCUMENT_ID>",
|
||||
data: [:],
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
transactionId: "<TRANSACTION_ID>" // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ let functions = Functions(client)
|
||||
|
||||
let executionList = try await functions.listExecutions(
|
||||
functionId: "<FUNCTION_ID>",
|
||||
queries: [] // optional
|
||||
queries: [], // optional
|
||||
total: false // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@ let file = try await storage.createFile(
|
||||
bucketId: "<BUCKET_ID>",
|
||||
fileId: "<FILE_ID>",
|
||||
file: InputFile.fromPath("file.png"),
|
||||
permissions: ["read("any")"] // optional
|
||||
permissions: [Permission.read(Role.any())] // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ let storage = Storage(client)
|
||||
let fileList = try await storage.listFiles(
|
||||
bucketId: "<BUCKET_ID>",
|
||||
queries: [], // optional
|
||||
search: "<SEARCH>" // optional
|
||||
search: "<SEARCH>", // optional
|
||||
total: false // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@ let file = try await storage.updateFile(
|
||||
bucketId: "<BUCKET_ID>",
|
||||
fileId: "<FILE_ID>",
|
||||
name: "<NAME>", // optional
|
||||
permissions: ["read("any")"] // optional
|
||||
permissions: [Permission.read(Role.any())] // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ let row = try await tablesDB.createRow(
|
||||
"age": 30,
|
||||
"isAdmin": false
|
||||
],
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
transactionId: "<TRANSACTION_ID>" // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ let rowList = try await tablesDB.listRows(
|
||||
databaseId: "<DATABASE_ID>",
|
||||
tableId: "<TABLE_ID>",
|
||||
queries: [], // optional
|
||||
transactionId: "<TRANSACTION_ID>" // optional
|
||||
transactionId: "<TRANSACTION_ID>", // optional
|
||||
total: false // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ let row = try await tablesDB.updateRow(
|
||||
tableId: "<TABLE_ID>",
|
||||
rowId: "<ROW_ID>",
|
||||
data: [:], // optional
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
transactionId: "<TRANSACTION_ID>" // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ let row = try await tablesDB.upsertRow(
|
||||
tableId: "<TABLE_ID>",
|
||||
rowId: "<ROW_ID>",
|
||||
data: [:], // optional
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
transactionId: "<TRANSACTION_ID>" // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ let teams = Teams(client)
|
||||
let membershipList = try await teams.listMemberships(
|
||||
teamId: "<TEAM_ID>",
|
||||
queries: [], // optional
|
||||
search: "<SEARCH>" // optional
|
||||
search: "<SEARCH>", // optional
|
||||
total: false // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ let teams = Teams(client)
|
||||
|
||||
let teamList = try await teams.list(
|
||||
queries: [], // optional
|
||||
search: "<SEARCH>" // optional
|
||||
search: "<SEARCH>", // optional
|
||||
total: false // optional
|
||||
)
|
||||
|
||||
|
||||
@@ -8,4 +8,5 @@ Account account = Account(client);
|
||||
|
||||
IdentityList result = await account.listIdentities(
|
||||
queries: [], // optional
|
||||
total: false, // optional
|
||||
);
|
||||
|
||||
@@ -8,4 +8,5 @@ Account account = Account(client);
|
||||
|
||||
LogList result = await account.listLogs(
|
||||
queries: [], // optional
|
||||
total: false, // optional
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:appwrite/appwrite.dart';
|
||||
import 'package:appwrite/permission.dart';
|
||||
import 'package:appwrite/role.dart';
|
||||
|
||||
Client client = Client()
|
||||
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
|
||||
@@ -17,6 +19,6 @@ Document result = await databases.createDocument(
|
||||
"age": 30,
|
||||
"isAdmin": false
|
||||
},
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
transactionId: '<TRANSACTION_ID>', // optional
|
||||
);
|
||||
|
||||
@@ -11,4 +11,5 @@ DocumentList result = await databases.listDocuments(
|
||||
collectionId: '<COLLECTION_ID>',
|
||||
queries: [], // optional
|
||||
transactionId: '<TRANSACTION_ID>', // optional
|
||||
total: false, // optional
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:appwrite/appwrite.dart';
|
||||
import 'package:appwrite/permission.dart';
|
||||
import 'package:appwrite/role.dart';
|
||||
|
||||
Client client = Client()
|
||||
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
|
||||
@@ -11,6 +13,6 @@ Document result = await databases.updateDocument(
|
||||
collectionId: '<COLLECTION_ID>',
|
||||
documentId: '<DOCUMENT_ID>',
|
||||
data: {}, // optional
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
transactionId: '<TRANSACTION_ID>', // optional
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:appwrite/appwrite.dart';
|
||||
import 'package:appwrite/permission.dart';
|
||||
import 'package:appwrite/role.dart';
|
||||
|
||||
Client client = Client()
|
||||
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
|
||||
@@ -11,6 +13,6 @@ Document result = await databases.upsertDocument(
|
||||
collectionId: '<COLLECTION_ID>',
|
||||
documentId: '<DOCUMENT_ID>',
|
||||
data: {},
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
transactionId: '<TRANSACTION_ID>', // optional
|
||||
);
|
||||
|
||||
@@ -9,4 +9,5 @@ Functions functions = Functions(client);
|
||||
ExecutionList result = await functions.listExecutions(
|
||||
functionId: '<FUNCTION_ID>',
|
||||
queries: [], // optional
|
||||
total: false, // optional
|
||||
);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'dart:io';
|
||||
import 'package:appwrite/appwrite.dart';
|
||||
import 'package:appwrite/permission.dart';
|
||||
import 'package:appwrite/role.dart';
|
||||
|
||||
Client client = Client()
|
||||
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
|
||||
@@ -11,5 +13,5 @@ File result = await storage.createFile(
|
||||
bucketId: '<BUCKET_ID>',
|
||||
fileId: '<FILE_ID>',
|
||||
file: InputFile(path: './path-to-files/image.jpg', filename: 'image.jpg'),
|
||||
permissions: ["read("any")"], // optional
|
||||
permissions: [Permission.read(Role.any())], // optional
|
||||
);
|
||||
|
||||
@@ -10,4 +10,5 @@ FileList result = await storage.listFiles(
|
||||
bucketId: '<BUCKET_ID>',
|
||||
queries: [], // optional
|
||||
search: '<SEARCH>', // optional
|
||||
total: false, // optional
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user