//! Choosing what one hears of from the pages: watching a repository, and //! subscribing to or muting an issue, each kept by the appview for the //! account alone, and shown back on the repository's and the issue's //! pages. use super::*; /// The `name=value` of the session cookie a login set. fn session(set: &[String]) -> String { let found = set.iter().find(|c| c.starts_with("knotless_session=")); pair(found.unwrap()).to_string() } #[test] fn watching_and_subscribing_from_the_pages() { // Started first, so its index sees the repositories made after. let server = gateway_with(None, true); let owner = person(account()); let url = owner.url("watched"); let work = owner.work("w", 1); owner.git(&work, &["push", "-q", &url, "main"]); let (code, issue) = owner.cli(&["issue", "create", &url, "Slow", "-m", "It is."], b""); assert_eq!(code, 0, "{issue}"); let repo = format!("at://{}/dev.knotless.repo/watched", owner.account.did); let xrpc = |nsid: &str| format!("{}/xrpc/dev.knotless.{nsid}", server.base); let thread = |cookie: Option<&str>| { let url = format!("{}?repo={repo}&uri={issue}", xrpc("getThread")); browse("GET", &url, cookie, None, None).2 }; let get_repo = |cookie: Option<&str>| { let url = format!("{}?repo={repo}", xrpc("getRepo")); browse("GET", &url, cookie, None, None).2 }; let put = |cookie: Option<&str>, subject: &str, level: &str| { let body = json!({"subject": subject, "level": level}); browse("POST", &xrpc("putSubscription"), cookie, None, Some(body)) }; let list = |cookie: Option<&str>, query: &str| { let url = format!("{}{query}", xrpc("listSubscriptions")); browse("GET", &url, cookie, None, None) }; wait_until(|| thread(None)["item"]["title"] == "Slow"); let watcher = person(account()); let mine = session(&log_in(&server, &watcher.account, "")); let me = Some(mine.as_str()); let theirs = session(&log_in(&server, &owner.account, "")); let owning = Some(theirs.as_str()); // Nothing chosen: it hears of the issue only when mentioned, and its // author as its author. assert_eq!(thread(me)["viewer"].get("notifiedFor"), None); assert_eq!(thread(owning)["viewer"]["notifiedFor"], "author"); assert_eq!(get_repo(me)["viewer"].get("subscription"), None); assert_eq!(list(me, "").2, json!({"subscriptions": []})); // Watching the repository, it hears of the issue as watching. let (status, _, now) = put(me, &repo, "all"); assert_eq!(status, 200, "{now}"); assert_eq!( (&now["subject"], &now["level"]), (&json!(repo), &json!("all")) ); assert!(now["createdAt"].is_string()); assert_eq!(get_repo(me)["viewer"]["subscription"], "all"); assert_eq!(thread(me)["viewer"]["notifiedFor"], "watching"); // Subscribed to the issue, then muted, as it chose. assert_eq!(put(me, &issue, "subscribed").2["level"], "subscribed"); assert_eq!(thread(me)["viewer"]["subscription"], "subscribed"); assert_eq!(put(me, &issue, "muted").2["level"], "muted"); assert_eq!(thread(me)["viewer"]["subscription"], "muted"); // Having commented, it hears of the thread as one who did. let said = json!({"repo": repo, "subject": issue, "body": "Same here."}); let commented = browse("POST", &xrpc("createComment"), me, None, Some(said)); assert_eq!(commented.0, 200, "{}", commented.2); assert_eq!(thread(me)["viewer"]["notifiedFor"], "commented"); // Listed, the latest choice first, a page at a time. let all = list(me, "").2; let subjects: Vec<&str> = all["subscriptions"] .as_array() .unwrap() .iter() .map(|s| s["subject"].as_str().unwrap()) .collect(); assert_eq!(subjects, [issue.as_str(), repo.as_str()]); let first = list(me, "?limit=1").2; assert_eq!(first["subscriptions"].as_array().unwrap().len(), 1); assert_eq!(first["cursor"], "1"); let next = list(me, "?limit=1&cursor=1").2; assert_eq!(next["subscriptions"][0]["subject"], repo.as_str()); assert_eq!(next.get("cursor"), None); assert_eq!(list(me, "?cursor=x").0, 400); // Forgotten, as participating. let forgot = put(me, &repo, "participating").2; assert_eq!(forgot, json!({"subject": repo, "level": "participating"})); assert_eq!(get_repo(me)["viewer"].get("subscription"), None); // Refused: a level the subject cannot take, what is no repository, // pull or issue, a repository there is none of, no one asking, and // from another site. assert_eq!(put(me, &repo, "muted").0, 400); assert_eq!(put(me, &issue, "all").0, 400); let comment = commented.2["uri"].as_str().unwrap().to_string(); assert_eq!(put(me, &comment, "subscribed").0, 400); assert_eq!(put(me, "nowhere", "all").0, 400); let gone = format!("at://{}/dev.knotless.repo/none", owner.account.did); assert_eq!(put(me, &gone, "all").0, 404); assert_eq!(put(None, &repo, "all").0, 401); assert_eq!(list(None, "").0, 401); let body = Some(json!({"subject": repo, "level": "all"})); let away = Some("https://evil.example"); assert_eq!( browse("POST", &xrpc("putSubscription"), me, away, body).0, 403 ); }