mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-31 07:39:20 +00:00
M9: team links the list no longer hands out are removed at startup; a team link is made before the list changes
This commit is contained in:
5 files changed
+55
-4
No files matched your search
@@ -431,6 +431,7 @@ impl Store {
|
||||
pub fn open(root: &Path, cfg: StoreConfig) -> Result<Store, String> {
|
||||
let mut store = Self::try_open(root, cfg)?.ok_or_else(|| format!("another figcraft-server (or a command) is using {}", root.display()))?;
|
||||
store.sweep();
|
||||
store.drop_stale_team_links();
|
||||
Ok(store)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,13 +51,14 @@ impl Store {
|
||||
if let Some(made) = made {
|
||||
return Ok(made);
|
||||
}
|
||||
// Made before the list changes: a failure leaves the links as they were.
|
||||
let (mut link, token) = new_link(access, &label(access), now())?;
|
||||
let before = entry.links.clone();
|
||||
entry.links.retain(|l| l.team.is_none());
|
||||
if entry.links.len() >= max {
|
||||
entry.links = before;
|
||||
return Err(format!("a file has at most {max} links: revoke one first"));
|
||||
}
|
||||
let (mut link, token) = new_link(access, &label(access), now())?;
|
||||
link.team = Some(TeamToken(token.clone()));
|
||||
entry.links.push(link.clone());
|
||||
if let Err(e) = write_json(&path, &entry.links) {
|
||||
@@ -68,6 +69,27 @@ impl Store {
|
||||
Ok(NewLink { link: link.info(file), token })
|
||||
}
|
||||
|
||||
/// At startup: the team links the list doesn't hand out now (it is off, or gives another
|
||||
/// access) are removed for good, so setting `team_files` back doesn't bring them back. Nobody
|
||||
/// keeps a team link's token for later (a team list link names none), so nothing is lost: the
|
||||
/// next join makes a new one. One that can't be removed stays refused at the door, and the
|
||||
/// operator is told.
|
||||
pub(super) fn drop_stale_team_links(&mut self) {
|
||||
let team = self.cfg.hosting.team;
|
||||
let stale = |l: &super::Link| l.team.is_some() && team != Some(l.access);
|
||||
let files: Vec<String> = self.files.iter().filter(|(_, e)| e.links.iter().any(stale)).map(|(id, _)| id.clone()).collect();
|
||||
for file in files {
|
||||
let path = self.dir(&file).join(LINKS);
|
||||
let Some(entry) = self.files.get_mut(&file) else { continue };
|
||||
entry.links.retain(|l| !stale(l));
|
||||
if let Err(e) = write_json(&path, &entry.links) {
|
||||
self.note(format!(
|
||||
"file {file}: its old team links couldn't be removed ({e}); they are refused, but would work again if team_files were set back to their access"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `file` stopped being shared (a link was revoked): revoke its team links too. The ids
|
||||
/// revoked (whoever joined with them is disconnected); none while it is still shared.
|
||||
pub(super) fn team_unshared(&mut self, file: &str) -> Vec<String> {
|
||||
|
||||
@@ -171,10 +171,35 @@ fn turning_the_list_off_or_changing_its_access_refuses_old_team_links() {
|
||||
pump(&mut [&mut b], "Bob in, view only", |s| live(s[0]) && s[0].live_summary()["access"] == "view");
|
||||
drop(b);
|
||||
drop(server);
|
||||
// Off: the list is gone and its links with it.
|
||||
// Off: the list is gone and its links with it, also from the file's links.
|
||||
let server = crate::start(&Config { open_publish: true, ..config(dir.path()) }).unwrap();
|
||||
let mut b = join(&invite(server.addr(), &file, &view), "Bob");
|
||||
pump(&mut [&mut b], "the team link refused", |s| refused(s[0]));
|
||||
drop(b);
|
||||
drop(server);
|
||||
assert!(!std::fs::read_to_string(dir.path().join("files").join(&file).join("links.json")).unwrap().contains(r#""team""#));
|
||||
// On again with the old access: the old links stay refused; the next join gets a new one.
|
||||
let server = crate::start(&team(dir.path(), "view")).unwrap();
|
||||
let mut b = join(&invite(server.addr(), &file, &view), "Bob");
|
||||
pump(&mut [&mut b], "the old view team link still refused", |s| refused(s[0]));
|
||||
assert_ne!(team_link(server.addr(), &file).unwrap(), view);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_team_link_never_handed_out_again_stays_refused_after_the_setting_goes_back() {
|
||||
let dir = TempDir::new("team-back");
|
||||
let mut server = crate::start(&team(dir.path(), "edit")).unwrap();
|
||||
let (a, file) = share(server.addr(), "Homepage");
|
||||
let edit = team_link(server.addr(), &file).unwrap();
|
||||
drop(a);
|
||||
server.stop();
|
||||
// View only for a while, and nobody asks for the view team link…
|
||||
drop(crate::start(&team(dir.path(), "view")).unwrap());
|
||||
// …then edit again: the edit team link of before doesn't come back.
|
||||
let server = crate::start(&team(dir.path(), "edit")).unwrap();
|
||||
let mut b = join(&invite(server.addr(), &file, &edit), "Bob");
|
||||
pump(&mut [&mut b], "the old edit team link refused", |s| refused(s[0]));
|
||||
assert_ne!(team_link(server.addr(), &file).unwrap(), edit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -684,7 +684,8 @@ resuming with its offline edits, and leaving the session going back to snapshot
|
||||
- **Revoking.** Revoking a link (`Admin revoke`) that leaves the file without a coded link revokes
|
||||
its team links too, in the same answer (`Handled::revoked` names every link revoked), so whoever
|
||||
joined with one is disconnected. Admission refuses a team link while the list is off, gives
|
||||
another access, or the file isn't shared, whatever `links.json` still holds.
|
||||
another access, or the file isn't shared, whatever `links.json` still holds, and the server
|
||||
removes such team links when it starts.
|
||||
|
||||
*Built* (document sync between apps):
|
||||
|
||||
|
||||
+3
-1
@@ -193,7 +193,9 @@ someone in, so keep it off on a server open to anyone.
|
||||
`<web_url>#join=<the link, escaped>`, which opens the file in the browser.
|
||||
- **Stopping.** When the last of a file's links with a code is revoked (Stop sharing does), its
|
||||
team link is revoked with it and whoever joined with it is disconnected, as with the other
|
||||
links. Turning the list off, or changing `team_files`, refuses the old team links at once.
|
||||
links. Turning the list off, or changing `team_files`, refuses the old team links at once, and
|
||||
the next start removes them for good (setting it back doesn't bring them back; the next join
|
||||
makes a new one).
|
||||
- **What the server keeps.** Unlike other links, a team link's token is kept readable in the
|
||||
file's `links.json`, so the server can hand it out: as private as the server key beside it.
|
||||
- **Upgrade note.** An app older than the team list shows no list and can't open its links (it
|
||||
|
||||
Reference in new issue
Block a user