Commit Graph
26 Commits
Author SHA1 Message Date
Lauri Ojansivu 5a1c9a61e9 Admin Panel / Problems "Status" overview + snap run wekan.problems: show migrations/repairs in progress and login-page "Must be logged in" causes; run repairs server-side.
Motivated by the 10.16-10.21 reports where, after an upgrade, the login page
showed "Must be logged in" or sat on the logo + "Loading, please wait." spinner,
pages took 5+ minutes, All Boards counts stayed 0 and i18n showed raw keys — the
FerretDB v1 (SQLite) process pegged ~2 cores for a long time under WeKan's poll
load, i.e. a migration/repair or a saturated backend, with no way to see it
without the Admin Panel.

Server-side, independent of any client / progress page:
 - server/startup/repairBoardsOnStartup.js runs the shared board data-repairs once
   (version-gated, background, 30s after boot) so corrupted data is fixed even if
   no user opens a board and nobody watches a progress page.
 - The MongoDB <-> SQLite text migration and the startup repair now PERSIST their
   progress to the text_migration_status collection (models/textMigrationStatus.js),
   so a separate process can see "a migration/repair is in progress" (an in-memory
   object could not).

Status overview (server/lib/systemStatus.js), shown in Admin Panel / Problems ->
Summary and via the method systemStatusReport (admin-gated, server/methods/
systemStatus.js):
 - everything in progress (text migration, board repair, recovery, cron migration,
   attachment migration) aggregated from the persisted status collections;
 - detected problems (broken cards; failing login-page checks);
 - login-page "Must be logged in" / "Loading, please wait" cause checklist
   (migration in progress, ROOT_URL, LDAP, Sandstorm) — models/lib/loginProblems.js;
 - a CPU detail area that calls out a pegged ferretdb process and the mitigation.

Snap: `snap run wekan.problems` (snap-src/bin/wekan-problems[.mjs], snapcraft app
`problems`) prints the same overview as text — problems, migrations/repairs in
progress, login checks — so an admin with only server access can see it WITHOUT
Admin Panel access. Sub-commands: migrations | login | broken-cards | cpu | help.

Pure helpers models/lib/loginProblems.js and models/lib/problemsOverview.js are
unit-tested; tests/problemsStatus.test.cjs (14 checks) also source-guards the
server hub, method, startup pass, migration persistence and snap command.

Thanks to xet7 !
2026-07-22 16:22:39 +03:00
Lauri Ojansivu 136a14c88a Shared board data-repairs run on board open AND during the MongoDB <-> SQLite migration, shown in one blue, Product-name-branded progress dashboard.
The board-open self-heal is broadened from the #6484 list-unbind alone to a
shared repair set (models/lib/boardRepair.js planner + server/lib/repairBoardData.js):

 - #6484: lists wrongly bound to a swimlane -> cleared back to board-wide, so the
   list stops "disappearing" from the other swimlanes;
 - cards with no swimlaneId (null/''/missing), which never render in the Swimlanes
   view -> assigned to the board's first swimlane;
 - orphaned cards whose swimlaneId points at a DELETED swimlane (invisible cards)
   -> reassigned to the first swimlane. A card on an existing but archived swimlane
   is NOT treated as orphaned.

The same repair set now runs in BOTH places:
 - Board open: boardBody.js maybeRepairBoard -> boardRepairNeeded / repairBoardData
   (server/methods/repairBoardData.js), once per board, admin-gated, fire-and-forget.
 - MongoDB <-> FerretDB v1 (SQLite) text migration: migrateTextDatabase runs
   repairAllBoards() on the live database BEFORE copying, so the migrated copy is
   clean too. It reports a new "repairing" phase (boardsDone/boardsTotal/repaired).

Both flows drive ONE shared progress dashboard (migrationProgress), now:
 - mounted app-wide (defaultLayout) so it shows for an Admin Panel database
   migration as well as a board-open repair;
 - fed from the DB-migration status poll (attachments.js driveMigrationDashboard);
 - styled in WeKan blue (#2980b9) instead of the old purple/green;
 - branded with the configured Product name (from the earlier commit).

Tests: tests/boardRepair.test.cjs (planner + server/migration/dashboard source
guards, 11 checks) and the updated tests/listUnbindRepair.test.cjs pass.

Thanks to xet7 !
2026-07-22 16:22:39 +03:00
Lauri Ojansivu 664c6e1943 Sandstorm: Admin Panel / Attachments / Sandstorm migration panel
When isSandstorm, show a new Sandstorm section in Admin Panel / Attachments:
one-time MongoDB 3 -> FerretDB migration status, disk space used by the raw
MongoDB 3 files / FerretDB SQLite / attachments / avatars in the grain, and a
guarded button to delete the redundant raw MongoDB files (only after a
confirmed-successful migration, behind a confirm) to free grain disk space.

- server/methods/sandstormMigration.js: admin-gated sandstormMigrationStatus
  + sandstormDeleteRawMongo (isSandstorm-gated, env-overridable grain paths).
- client Attachments: new Sandstorm tab (jade + js), shown only when isSandstorm.
- imports/i18n/data/en.i18n.json: sandstorm-* UI strings.
- migrate-mongo3-to-ferretdb.mjs: optional STATUS_FILE with the final migration
  state, which the panel reads (shared by snap + the Sandstorm spk).
2026-07-11 04:39:24 +03:00
Lauri Ojansivu 011c172c8c Fix scheduled backup cron init crashing at Meteor 3 server startup
registerCron() used the synchronous BackupSettings.findOne/upsert, which
Meteor 3 forbids on the server, so cron init threw and scheduled backups
never registered. Use findOneAsync/upsertAsync, make registerCron async,
and await it in all callers. Add tests/backupCron.test.cjs (positive +
negative + source guard) to the test:unit:node suite.
2026-07-11 01:53:07 +03:00
xet7 abe8af0788 Fix backup build: archiver@8 ESM (ZipArchive) + add @aws-sdk/lib-storage dep
The Meteor/rspack build failed on server/methods/backup.js:
- archiver@8 is now pure ESM with no default export and no archiver('zip', …)
  factory — it exports classes. Use `import { ZipArchive } from 'archiver'` and
  `new ZipArchive({ zlib: { level: 6 } })` (the streaming API — directory/append/
  finalize/pipe/on — is inherited from the Archiver core class).
- The S3 streaming upload requires @aws-sdk/lib-storage, which was not a
  dependency (only @aws-sdk/client-s3 was), so rspack failed with
  "Can't resolve '@aws-sdk/lib-storage'". Add it, pinned to ~3.1073.0 to match
  the installed @aws-sdk/client-s3 (3.1073.0) and avoid the newer lib-storage's
  peer requirement on a newer client-s3.
2026-07-11 01:31:05 +03:00
xet7 d2ec3ee400 Unit + negative tests for newest features (lazy loading, streaming export, backup)
Extract the pure, security- and correctness-critical logic of the recent features
into Meteor-free models/lib/* modules (so production and tests share one
implementation) and add plain-Node tests with positive AND negative cases, wired
into test:unit:node:

- models/lib/mongoSelectorSafety.js hasWhere() — the windowed card publication
  refuses a client selector carrying $where (server-side JS). Tests: safe
  selectors pass; $where at top level / in $and / deep in arrays / in $elemMatch
  is rejected. (was inline in server/publications/cardsWindow.js)
- models/lib/cardsLoading.js resolveCardsLoadingMode / parseCardsLoadingEnv /
  windowCountId — CARDS_LOADING maps to 'lazy' only for exactly "lazy" (garbage
  never enables the experimental mode); a falsy swimlane id collapses to one
  count-doc id (listBody uses undefined, listHeader uses ''). (used by
  server/cards-loading.js, server/models/settings.js, client/lib/lazyCards.js)
- models/lib/base64Chunk.js encodeAligned/encodeFinal — streaming an attachment
  into the JSON export as base64 in any chunk sizes reconstructs exactly the
  whole-file base64; aligned pieces never carry padding. (used by
  Exporter.buildStream)
- models/lib/backupPaths.js filesRootFrom/scheduleText — WRITABLE_PATH -> files
  root (no double /files suffix, Windows-safe) and the synced-cron schedule text
  (daily/weekly/monthly + defaults, unknown frequency falls back to daily). (used
  by server/methods/backup.js)

41 new assertions across 4 files, all passing; whole test:unit:node suite green.
2026-07-11 00:14:49 +03:00
xet7 e39dcd4ebf Backup: switch from jszip to archiver+unzipper for low-memory streaming
Admin Panel / Attachments / Backup no longer loads whole files or the whole
zip into memory. The backup zip is written with archiver, streaming each
attachment/avatar straight from disk (archive.directory) and each text
collection a document at a time from a Mongo cursor as NDJSON, piped directly
to the destination (filesystem or S3/Azure/GCS streaming upload) with no temp
file. Restore reads the zip with unzipper, piping each file entry to disk and
each NDJSON data entry line-by-line in 200-doc batches. A board with thousands
of cards or a 5 GB attachment now backs up/restores with flat memory.
2026-07-10 22:57:40 +03:00
xet7 c7c8a200ff Admin Panel / Attachments / Backup: scheduled backups of Attachments/Avatars/Data, streamed to storage; restore + list
Adds a Backup section to Admin Panel / Attachments:
- Checkboxes to select Attachments, Avatars and/or Data (all text-based
  collections that are not attachments/avatars).
- Storage dropdown (filesystem, S3/MinIO, Azure, GCS).
- Backup now: the .zip is STREAMED DIRECTLY to the selected storage — no temp
  file, no extra disk — as backup/YYYY/MM/DD/HH_MM_SS/backup.zip containing
  YYYY_MM_DD-HH_MM_SS/{attachments,avatars,data/<collection>.json}. Filesystem
  pipes to the file; S3 uses @aws-sdk/lib-storage streaming Upload, Azure
  uploadStream, GCS createWriteStream (cloud creds from the storage tabs).
- Scheduler (off/daily/weekly/monthly + time/day) saved and run via synced-cron.
- List backups: table with storage, datetime, path; select one and Restore with
  "Add missing data only" or "Replace all data".

Server methods (admin-only): runBackup, restoreBackup, listBackups,
getBackupSchedule, saveBackupSchedule, backupStatus (polled for live progress).

The cloud upload paths and restore are not exercised end-to-end here; the whole
zip is assembled with jszip, so very large attachment sets use notable memory.

Thanks to xet7.
2026-07-10 22:57:40 +03:00
xet7 84fee7b660 Admin Panel / Attachments: migrate text data between MongoDB and FerretDB v1 (SQLite), both directions
Adds a "Database migration" section to Admin Panel / Attachments with two buttons:
migrate text-based data (everything except attachments/avatars, which stay on the
filesystem) to FerretDB v1 (SQLite), or back to MongoDB.

WeKan is connected to one database at a time, so the new server methods open a
SECOND driver connection to the OTHER database (both MongoDB and FerretDB v1 speak
the MongoDB wire protocol) and copy the text collections from the live database
into it, upserting by _id (idempotent, re-runnable). The target URL is
WEKAN_FERRETDB_URL (default mongodb://127.0.0.1:27018/wekan) or WEKAN_MONGODB_URL
(default mongodb://127.0.0.1:27019/wekan); both must be running. Progress is polled
via migrateTextDatabaseStatus and shown live. After it finishes, point MONGO_URL at
the other database and restart (on Snap: snap set wekan database=ferretdb / =mongodb).

Admin-only. Attachments/avatars are skipped (they live on the filesystem).

Thanks to xet7.
2026-07-10 22:57:40 +03:00
Lauri OjansivuandClaude Opus 4.8 b4bbf2480a Add ICS import REST API + OpenAPI + api.py example (#6323)
Expose the iCalendar (.ics) import as a REST endpoint
POST /api/boards/:boardId/swimlanes/:swimlaneId/lists/:listId/ics (body { ics })
that reuses the shared import logic, requires board write access, and returns
{ created, cardIds }. Document it in the OpenAPI spec (openapi/extra_paths.yml,
spliced into public/api/wekan.yml) and add an 'importics' example command to
api.py. Note the new endpoint in the ChangeLog.

Note: OAUTH2_LOGOUT_ENDPOINT (the only new env var in the Upcoming changelog) is
already present in all deployment configs (Dockerfile, docker-compose.yml,
snap-src/bin/config, start-wekan.sh/.bat); rebuild-wekan.sh/.bat are dev-run
scripts with no OAUTH2 section, so nothing was added there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 20:58:36 +03:00
Lauri OjansivuandClaude Opus 4.8 0a43d8ac3c Add #6323: import Google Calendar .ics files into board cards (MVP)
New dependency-free iCalendar parser (server/lib/icsImport.js) maps each VEVENT
to a card with startAt/dueAt so events show on Calendar/Gantt views, plus an
importIcsToBoard Meteor method. Import-only; two-way Google Calendar sync is not
included. Parser unit tested (folded lines, escaping, all-day vs date-time, etc.).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 14:40:13 +03:00
Harry Adel 63ce45c538 Split shared models from Meteor 3 server runtime 2026-03-24 01:50:39 +02:00
Harry Adel f934aea2a5 Return data on client (sync) and Promise on server (async) naturally, without wrapping in an extra Promise 2026-02-18 18:24:55 +02:00
Harry Adel 5212f3beb3 Merge branch 'main' into feature/reactive-cache-async-migration 2026-02-17 16:45:06 +02:00
Lauri Ojansivu 1b8b8d2eef Reverted New UI Design of WeKan v8.29 and added more fixes and performance improvements.
Thanks to xet7 !
2026-02-08 00:48:39 +02:00
Harry Adel 71eb01e233 Update ReactiveCache call sites to use async/await for Meteor 3.0
Part 3 of ReactiveCache async migration:
- Add await before all ReactiveCache.getX() calls
- Make functions containing ReactiveCache calls async
- Convert forEach/map/filter loops with async callbacks to for...of
- Update model helpers, Meteor methods, JsonRoutes handlers
- Update collection hooks (.before/.after insert/update/remove)
- Update .allow() callbacks to async

Files updated across models/ and server/ directories:
- Model files: cards, boards, lists, swimlanes, activities, users,
  checklists, checklistItems, customFields, attachments, integrations,
  cardComments, settings files, creators, exporters, and more
- Server files: publications, methods, notifications, routes, migrations
2026-02-01 00:54:38 +02:00
Harry Adel b431600d32 Migrate accounts-lockout server files to async for Meteor 3.0
- lockedUsers.js: async getLockedUsers, unlockUser, unlockAllUsers
- lockoutSettings.js: async reloadAccountsLockout with findOneAsync
- accounts-lockout-config.js: async startup with findOneAsync
- models/lockoutSettings.js: upsert → upsertAsync
2026-01-29 21:29:56 +02:00
Lauri Ojansivu a419d831a4 Fix Filebleed of Floppybleed.
Thanks to Luke Hebenstreit Twitter lheben_ and xet7 !
2026-01-28 13:20:28 +02:00
Lauri Ojansivu 4ce181d172 Security Fix 12: FixDuplicateBleed.
Thanks to [Joshua Rogers](https://joshua.hu) of [Aisle Research](https://aisle.com) and xet7.
2026-01-18 20:07:12 +02:00
Lauri Ojansivu 55576ec177 Security Fix 5: PositionHistoryBleed.
Thanks to [Joshua Rogers](https://joshua.hu) of [Aisle Research](https://aisle.com) and xet7.
2026-01-18 19:29:58 +02:00
Lauri Ojansivu ae11e80bde Fix Regression - unable to view cards by due date v8.11.
Thanks to xet7 !

Fixes #5964
2025-10-22 23:31:36 +03:00
Lauri Ojansivu 58df525b49 Fix duplicated lists and do not show debug messages when env DEBUG is not true. Part 3.
Thanks to xet7 !

Fixes #5952
2025-10-21 15:31:34 +03:00
Lauri Ojansivu b7ca2310b2 Fix duplicated lists.
Thanks to xet7 !

Fixes #5952
2025-10-21 15:19:19 +03:00
Lauri Ojansivu b6e7b258e0 Fix duplicated lists.
Thanks to xet7 !

Fixes #5952
2025-10-21 15:14:01 +03:00
Lauri Ojansivu 2543df9425 Show original positions of swimlanes, lists and cards.
Thanks to xet7 !

Fixes #5939
2025-10-16 20:23:05 +03:00
Lauri Ojansivu ae0d059b6f Feature: Added brute force login protection settings to Admin Panel/People/Locked Users.
Added filtering of Admin Panel/People/People: All Users/Locked Users Only/Active/Not Active.
Added visual indicators: red lock icon for locked users, green check for active users, and red X for inactive users.
Added "Unlock All" button to quickly unlock all brute force locked users.
Added ability to toggle user active status directly from the People page.
Moved lockout settings from environment variables to database so admins can configure the lockout thresholds directly in the UI.

Thanks to xet7.
2025-08-05 00:31:43 +03:00