Skeletons for new files only; existing files change by exact edits, so no task overwrites an earlier one's work. Each task's tests were run against a reference built in order from master, with the gate at each step and mutations checked; each skeleton compiles and fails its tests, and every todo!() comment was read beside its signature. The reference is kept off this machine. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2.7 KiB
2.7 KiB
M4b task 09: editing a post, and a username
Branch: m4b (run git switch m4b; git status --short must be empty, otherwise stop)
Commit subject: gatewayd: mm, patch_post and username
Goal
When an approval ends, gatewayd edits its post to say how, naming who answered (M4b spec,
section 6). Two REST calls, checked against Mattermost v11.11.0, and confirmed on the owner's
server (the bot may edit its own posts):
PUT /api/v4/posts/{post_id}/patchwith{"message": "…"}: replaces the post's text; the answer is the post.GET /api/v4/users/{user_id}: the user, withusername.
Every id that goes into a path must be a Mattermost id first, or nothing is sent.
Files
- Copy:
crates/gatewayd/tests/mm_edit.rs - Modify:
crates/gatewayd/src/mm/rest.rs,docs/implementer-log.md
The changes, exactly
In crates/gatewayd/src/mm/rest.rs, after struct Channel:
#[derive(Deserialize)]
struct User {
username: String,
}
/// A Mattermost username: 1 to 64 characters of `a-z`, `0-9`, `.`, `-` and `_`.
fn valid_username(name: &str) -> bool {
(1..=64).contains(&name.len())
&& name.bytes().all(|b| {
b.is_ascii_lowercase() || b.is_ascii_digit() || matches!(b, b'.' | b'-' | b'_')
})
}
and two methods at the end of impl Client, written like posts_since and create_post:
pub fn patch_post(&self, post: &str, message: &str) -> Result<(), MmError>:postnotvalid_id:Err(MmError::Json("a post path must be a Mattermost id".to_string())), nothing sent.PUT/api/v4/posts/{post}/patchwith the bodyserde_json::json!({ "message": message }).to_string(), throughself.call.- The answer is a
Post:json::<Post>(&body)?.check().map(|_| ()).
pub fn username(&self, user: &str) -> Result<String, MmError>:usernotvalid_id:Err(MmError::Json("a user path must be a Mattermost id".to_string())).GET/api/v4/users/{user}intoUser; a username that is notvalid_usernameisErr(MmError::Json("the user has no valid username".to_string())). ElseOk(username).
Steps
- 1. Copy.
git switch m4b, thencp docs/plans/M4b/files/crates/gatewayd/tests/mm_edit.rs crates/gatewayd/tests/ - 2. See it fail.
cargo test -p gatewayd --test mm_edit. Expected: it does not compile. - 3. Make the changes. Run
cargo fmt --all. - 4. See it pass.
cargo test -p gatewayd --test mm_edit --test mm_rest. Expected: 4 and 10 passed. - 5. Run the gate.
make gate. Expected last line:gate: ok. - 6. Log and commit.
git add crates/gatewayd docs/implementer-log.md Cargo.lock && git commit
Done when
- Both suites pass;
make gateprintsgate: ok.