Update Cloudflare credential handling

This commit is contained in:
Tiago Yamamoto 2026-01-08 15:43:32 -03:00
parent 4fd54a9633
commit 02387f28c6
3 changed files with 33 additions and 5 deletions

View file

@ -284,6 +284,8 @@ Funções disponíveis:
- `hello-world`: Função exemplo - `hello-world`: Função exemplo
- `sync-github`: Sincroniza dados de repositórios GitHub - `sync-github`: Sincroniza dados de repositórios GitHub
- `check-cloudflare-status`: Verifica status de contas Cloudflare - `check-cloudflare-status`: Verifica status de contas Cloudflare
- Gere um **API Token** no Cloudflare com permissões **Zone:Read** e **Workers:Read**.
- Salve o token no Appwrite na coleção `cloud_accounts` com `provider=cloudflare`, `apiKey` e, opcionalmente, `cloudflareAccountId` (usado para listar Workers).
## 🏃 Executando o Projeto ## 🏃 Executando o Projeto

View file

@ -59,7 +59,6 @@ export default async function ({ req, res, log, error }) {
const payload = req.body ? JSON.parse(req.body) : {}; const payload = req.body ? JSON.parse(req.body) : {};
const accountId = payload.accountId; const accountId = payload.accountId;
const cloudflareAccountId = payload.cloudflareAccountId;
const requesterId = const requesterId =
(req.headers && (req.headers['x-appwrite-user-id'] || req.headers['x-appwrite-userid'])) || (req.headers && (req.headers['x-appwrite-user-id'] || req.headers['x-appwrite-userid'])) ||
process.env.APPWRITE_FUNCTION_USER_ID || process.env.APPWRITE_FUNCTION_USER_ID ||
@ -90,6 +89,8 @@ export default async function ({ req, res, log, error }) {
return res.json({ error: 'Cloudflare token is missing for this account.' }, 400); return res.json({ error: 'Cloudflare token is missing for this account.' }, 400);
} }
const cloudflareAccountId = payload.cloudflareAccountId || account.cloudflareAccountId;
const [zones, workers] = await Promise.all([ const [zones, workers] = await Promise.all([
fetchZones(token, log), fetchZones(token, log),
fetchWorkers(token, cloudflareAccountId, log) fetchWorkers(token, cloudflareAccountId, log)

View file

@ -27,9 +27,10 @@ type Worker = {
export default function Cloudflare() { export default function Cloudflare() {
const [label, setLabel] = useState('') const [label, setLabel] = useState('')
const [apiKey, setApiKey] = useState('') const [apiKey, setApiKey] = useState('')
const [credentialAccountId, setCredentialAccountId] = useState('')
const [accountId, setAccountId] = useState('') const [accountId, setAccountId] = useState('')
const [cloudflareAccountId, setCloudflareAccountId] = useState('') const [cloudflareAccountId, setCloudflareAccountId] = useState('')
const [credentials, setCredentials] = useState<{ $id: string; label: string }[]>([]) const [credentials, setCredentials] = useState<{ $id: string; label: string; cloudflareAccountId?: string }[]>([])
const [zones, setZones] = useState<Zone[]>([]) const [zones, setZones] = useState<Zone[]>([])
const [workers, setWorkers] = useState<Worker[]>([]) const [workers, setWorkers] = useState<Worker[]>([])
const [execution, setExecution] = useState<Models.Execution | null>(null) const [execution, setExecution] = useState<Models.Execution | null>(null)
@ -45,7 +46,11 @@ export default function Cloudflare() {
const response = await databases.listDocuments(appwriteDatabaseId, appwriteCollectionCloudflareAccountsId, [ const response = await databases.listDocuments(appwriteDatabaseId, appwriteCollectionCloudflareAccountsId, [
Query.equal('provider', 'cloudflare'), Query.equal('provider', 'cloudflare'),
]) ])
const docs = response.documents.map((doc) => ({ $id: doc.$id, label: (doc as { label?: string }).label || doc.$id })) const docs = response.documents.map((doc) => ({
$id: doc.$id,
label: (doc as { label?: string }).label || doc.$id,
cloudflareAccountId: (doc as { cloudflareAccountId?: string }).cloudflareAccountId,
}))
setCredentials(docs) setCredentials(docs)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
@ -86,10 +91,15 @@ export default function Cloudflare() {
provider: 'cloudflare', provider: 'cloudflare',
apiKey, apiKey,
label, label,
cloudflareAccountId: credentialAccountId || undefined,
}) })
setCredentials((prev) => [...prev, { $id: document.$id, label: label || document.$id }]) setCredentials((prev) => [
...prev,
{ $id: document.$id, label: label || document.$id, cloudflareAccountId: credentialAccountId || undefined },
])
setLabel('') setLabel('')
setApiKey('') setApiKey('')
setCredentialAccountId('')
} catch (err) { } catch (err) {
console.error(err) console.error(err)
setError('Não foi possível salvar a API Key.') setError('Não foi possível salvar a API Key.')
@ -167,6 +177,16 @@ export default function Cloudflare() {
className="mt-1 w-full rounded-lg border border-slate-800 bg-slate-950 px-3 py-2 text-sm text-slate-100 outline-none focus:border-cyan-400" className="mt-1 w-full rounded-lg border border-slate-800 bg-slate-950 px-3 py-2 text-sm text-slate-100 outline-none focus:border-cyan-400"
/> />
</div> </div>
<div>
<label className="text-sm text-slate-200">Cloudflare Account ID (opcional)</label>
<input
type="text"
value={credentialAccountId}
onChange={(e) => setCredentialAccountId(e.target.value)}
placeholder="Conta para listar Workers"
className="mt-1 w-full rounded-lg border border-slate-800 bg-slate-950 px-3 py-2 text-sm text-slate-100 outline-none focus:border-cyan-400"
/>
</div>
<button <button
type="submit" type="submit"
className="rounded-lg bg-cyan-500 px-4 py-2 text-sm font-semibold text-slate-900 transition hover:bg-cyan-400" className="rounded-lg bg-cyan-500 px-4 py-2 text-sm font-semibold text-slate-900 transition hover:bg-cyan-400"
@ -186,7 +206,12 @@ export default function Cloudflare() {
<label className="text-sm text-slate-200">Credencial</label> <label className="text-sm text-slate-200">Credencial</label>
<select <select
value={accountId} value={accountId}
onChange={(e) => setAccountId(e.target.value)} onChange={(e) => {
const selected = e.target.value
setAccountId(selected)
const selectedCredential = credentials.find((cred) => cred.$id === selected)
setCloudflareAccountId(selectedCredential?.cloudflareAccountId || '')
}}
className="mt-1 w-full rounded-lg border border-slate-800 bg-slate-950 px-3 py-2 text-sm text-slate-100 outline-none focus:border-cyan-400" className="mt-1 w-full rounded-lg border border-slate-800 bg-slate-950 px-3 py-2 text-sm text-slate-100 outline-none focus:border-cyan-400"
> >
<option value="">Selecione um documento</option> <option value="">Selecione um documento</option>