feat: Gitea Webhook, IMAP, Settings & Deployment docs

- Webhook route and Gitea integration
- IMAP service and Nextcloud/Porkbun setup docs
- Settings UI improvements and API updates
- SSH/Webhook fix prompt for emailsorter.webklar.com
- Bootstrap, config and AI sorter updates
This commit is contained in:
2026-01-31 15:00:00 +01:00
parent 7e7ec1013b
commit cbb225c001
24 changed files with 2173 additions and 32 deletions

View File

@@ -0,0 +1,75 @@
/**
* Create admin user in Appwrite (e.g. support@webklar.com).
* Requires: APPWRITE_* env vars. Optionally ADMIN_INITIAL_PASSWORD (otherwise one is generated).
* After creation, add the email to ADMIN_EMAILS in .env so the backend treats them as admin.
*
* Usage: node scripts/create-admin-user.mjs [email]
* Default email: support@webklar.com
*/
import 'dotenv/config'
import { Client, Users, ID } from 'node-appwrite'
const ADMIN_EMAIL = process.argv[2] || 'support@webklar.com'
const ADMIN_NAME = 'Support (Admin)'
const required = ['APPWRITE_ENDPOINT', 'APPWRITE_PROJECT_ID', 'APPWRITE_API_KEY']
for (const k of required) {
if (!process.env[k]) {
console.error(`Missing env: ${k}`)
process.exit(1)
}
}
let password = process.env.ADMIN_INITIAL_PASSWORD
if (!password || password.length < 8) {
const bytes = new Uint8Array(12)
if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.getRandomValues) {
globalThis.crypto.getRandomValues(bytes)
} else {
const { randomFillSync } = await import('node:crypto')
randomFillSync(bytes)
}
password =
Array.from(bytes).map((b) => 'abcdefghjkmnpqrstuvwxyz23456789'[b % 32]).join('') + 'A1!'
console.log('No ADMIN_INITIAL_PASSWORD set using generated password (save it!):')
console.log(' ' + password)
console.log('')
}
const client = new Client()
.setEndpoint(process.env.APPWRITE_ENDPOINT)
.setProject(process.env.APPWRITE_PROJECT_ID)
.setKey(process.env.APPWRITE_API_KEY)
const users = new Users(client)
async function main() {
try {
const existing = await users.list([], ADMIN_EMAIL)
const found = existing.users?.find((u) => u.email?.toLowerCase() === ADMIN_EMAIL.toLowerCase())
if (found) {
console.log(`User already exists: ${ADMIN_EMAIL} (ID: ${found.$id})`)
console.log('Add to server/.env: ADMIN_EMAILS=' + ADMIN_EMAIL)
return
}
const user = await users.create(ID.unique(), ADMIN_EMAIL, undefined, password, ADMIN_NAME)
console.log('Admin user created:')
console.log(' Email:', user.email)
console.log(' ID:', user.$id)
console.log(' Name:', user.name)
console.log('')
console.log('Add to server/.env: ADMIN_EMAILS=' + ADMIN_EMAIL)
console.log('Then the backend will treat this user as admin (isAdmin() returns true).')
} catch (err) {
console.error('Error:', err.message || err)
if (err.code === 409) {
console.error('User with this email may already exist. Check Appwrite Console → Auth → Users.')
}
process.exit(1)
}
}
main()