mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 01:54:10 +00:00
Publish latest from release tags, add a changelog, unstale the roadmap
latest followed the default branch, so every push to main went straight to the tag the README tells people to pull — including work in progress, and migrations that run automatically on boot. It now moves only on a v* tag; main still publishes under its own name for anyone wanting the tip. The roadmap listed three finished things as open, including the label refactor and the nested label UI, both of which shipped. A roadmap that under-reports is worse than none: it is the document a contributor reads to decide what to pick up. Corrected, with the genuinely open items described accurately and a note asking that it be kept honest. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ddccc8fa2e
commit
dc0647f23f
5 files changed
+84
-7
No files matched your search
@@ -3,6 +3,9 @@ name: Build and push Docker image
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
# Releases. `latest` moves only when one of these is pushed — see the
|
||||
# tag rules in the merge job.
|
||||
tags: ['v*']
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
@@ -122,10 +125,19 @@ jobs:
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
# `latest` used to follow the default branch, so every push
|
||||
# to main went straight to the tag the README tells people to
|
||||
# pull — including work in progress, and migrations that run
|
||||
# automatically on boot. It now moves only on a release tag.
|
||||
#
|
||||
# `main` still publishes, under its own name, for anyone who
|
||||
# wants the tip.
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=sha,prefix=sha-
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: ${{ runner.temp }}/digests
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# Changelog
|
||||
|
||||
Notable changes per release. plMail runs its migrations automatically on boot,
|
||||
so anything that changes the schema irreversibly is called out explicitly.
|
||||
|
||||
The published image tags: `latest` follows the most recent release below,
|
||||
`main` follows the tip of the default branch, and `sha-…` pins one commit.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- **Snooze.** Put a conversation away and have it come back later — from the
|
||||
message row, the list toolbar, or a JMAP client via the `Thread/set`
|
||||
extension. Snoozed conversations get their own sidebar entry and view.
|
||||
`app:mail:wake-snoozed` runs every minute to bring them back.
|
||||
- **JMAP draft attachments.** `Email/set` now accepts uploaded blobs in
|
||||
`attachments`, per RFC 8621; drafts created over JMAP previously dropped them
|
||||
silently.
|
||||
- **Login throttling.** Five attempts per account per fifteen minutes on the
|
||||
password form, and a separate limit on the two-factor code form — which the
|
||||
firewall's throttling does not cover, and which is the form an attacker
|
||||
reaches holding a stolen password.
|
||||
- **PHPStan** at level 5, with a baseline, in CI. **Dependabot** for composer,
|
||||
npm and GitHub Actions.
|
||||
- **LICENSE.** The project has always said AGPL-3.0 in its README; the licence
|
||||
text is now actually distributed with it, and `composer.json` no longer
|
||||
contradicts it by claiming "proprietary".
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Snoozing from the web UI did nothing but set a timer.** No labels moved and
|
||||
nothing propagated, so the conversation stayed in the inbox — locally and at
|
||||
the provider — while its row vanished from the list. The sweep would then
|
||||
"wake" a thread that had never left.
|
||||
- **The snooze button on a message row cleared a snooze instead of setting
|
||||
one**, and the toolbar's snoozed everything to a hardcoded 8am tomorrow.
|
||||
- **"Test connection" in account settings crashed** with an `ArgumentCountError`
|
||||
whenever the form was incomplete or the password blank — the two cases it
|
||||
exists to report.
|
||||
- **The admin Graph category sync caught an exception class that does not
|
||||
exist**, so Graph failures propagated instead of degrading quietly.
|
||||
- **JMAP `Email/set` rejected valid mailbox patches.** Current `mailboxIds` were
|
||||
emitted as label ids where the protocol expects per-account binding ids; since
|
||||
both are autoincrement ints, a patch removing one mailbox failed with "No such
|
||||
Mailbox".
|
||||
|
||||
### Changed
|
||||
|
||||
- `latest` is published from release tags only. It previously followed every
|
||||
push to `main`, which meant the tag the README tells people to pull could
|
||||
carry unreviewed work and automatic schema migrations.
|
||||
- The login form no longer shows a "forgot password?" link. There is no reset
|
||||
flow — recovery is a console command — and the link was an `href="#"` that did
|
||||
nothing.
|
||||
+12
-5
@@ -317,11 +317,18 @@ each.
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [ ] Complete the label-based architecture refactor (Label as the user-facing concept; Mailbox demoted to IMAP sync infrastructure)
|
||||
- [x] Complete the label-based architecture refactor (Label as the user-facing concept; Mailbox demoted to IMAP sync infrastructure)
|
||||
- [x] Sanitize rendered HTML bodies
|
||||
- [x] Full-text search
|
||||
- [x] Microsoft OAuth2 / Graph send support
|
||||
- [ ] Gmail-native `threadId` threading (currently RFC Message-ID based)
|
||||
- [ ] Incoming IMAP flag sync over the IDLE stream
|
||||
- [ ] Avatar fetching (once OAuth avatar scopes are wired)
|
||||
- [ ] Nested label UI
|
||||
- [x] Nested label UI — `Label::$parent`, `LabelRepository::findVisibleTreeForUser()`, and the recursive tree in `_partials/_sidebar.html.twig`
|
||||
- [x] Snooze — `ThreadSnoozeService`, `app:mail:wake-snoozed`, and the `Thread/set` JMAP extension
|
||||
- [ ] Gmail-native `threadId` threading (the id is carried on `Message`, but threading is still RFC Message-ID based)
|
||||
- [ ] Incoming IMAP flag sync over the IDLE stream — flags currently travel outward only, so marking a message read in another client does not reflect back
|
||||
- [ ] Avatar fetching (partially done: `Service/User/AvatarFromIntegration.php`; still needs OAuth avatar scopes)
|
||||
- [ ] Per-identity signatures — no `signature` field exists on `User`, `Account` or `EmailAlias`
|
||||
- [ ] Password reset (recovery is console-only today, which is why the login form no longer offers a link)
|
||||
|
||||
> Keep this honest. Three items above were finished long before anyone ticked
|
||||
> them, and a roadmap that under-reports is worse than none — it is the document
|
||||
> a contributor reads to decide what to pick up.
|
||||
@@ -629,7 +629,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* }>,
|
||||
* },
|
||||
* rate_limiter?: bool|array{ // Rate limiter configuration
|
||||
* enabled?: bool|Param, // Default: false
|
||||
* enabled?: bool|Param, // Default: true
|
||||
* limiters?: array<string, array{ // Default: []
|
||||
* lock_factory?: scalar|Param|null, // The service ID of the lock factory used by this limiter (or null to disable locking). // Default: "auto"
|
||||
* cache_pool?: scalar|Param|null, // The cache pool to use for storing the current limiter state. // Default: "cache.rate_limiter"
|
||||
|
||||
@@ -62,6 +62,9 @@
|
||||
"config/packages/http_discovery.yaml"
|
||||
]
|
||||
},
|
||||
"phpstan/phpstan": {
|
||||
"version": "2.2.7"
|
||||
},
|
||||
"phpunit/phpunit": {
|
||||
"version": "13.2",
|
||||
"recipe": {
|
||||
|
||||
Reference in new issue
Block a user