PDS software with bells & whistles you didn’t even know you needed. will move this to its own account when ready.
at main 12 kB view raw
1mod common; 2use common::*; 3use reqwest::StatusCode; 4use serde_json::{Value, json}; 5 6#[tokio::test] 7async fn test_create_invite_code_success() { 8 let client = client(); 9 let (access_jwt, _did) = create_admin_account_and_login(&client).await; 10 let payload = json!({ 11 "useCount": 5 12 }); 13 let res = client 14 .post(format!( 15 "{}/xrpc/com.atproto.server.createInviteCode", 16 base_url().await 17 )) 18 .bearer_auth(&access_jwt) 19 .json(&payload) 20 .send() 21 .await 22 .expect("Failed to send request"); 23 assert_eq!(res.status(), StatusCode::OK); 24 let body: Value = res.json().await.expect("Response was not valid JSON"); 25 assert!(body["code"].is_string()); 26 let code = body["code"].as_str().unwrap(); 27 assert!(!code.is_empty()); 28 assert!( 29 code.contains('-'), 30 "Code should be in hostname-xxxxx-xxxxx format" 31 ); 32 let parts: Vec<&str> = code.split('-').collect(); 33 assert!( 34 parts.len() >= 3, 35 "Code should have at least 3 parts (hostname + 2 random parts)" 36 ); 37} 38 39#[tokio::test] 40async fn test_create_invite_code_no_auth() { 41 let client = client(); 42 let payload = json!({ 43 "useCount": 5 44 }); 45 let res = client 46 .post(format!( 47 "{}/xrpc/com.atproto.server.createInviteCode", 48 base_url().await 49 )) 50 .json(&payload) 51 .send() 52 .await 53 .expect("Failed to send request"); 54 assert_eq!(res.status(), StatusCode::UNAUTHORIZED); 55 let body: Value = res.json().await.expect("Response was not valid JSON"); 56 assert_eq!(body["error"], "AuthenticationRequired"); 57} 58 59#[tokio::test] 60async fn test_create_invite_code_non_admin() { 61 let client = client(); 62 let _ = create_admin_account_and_login(&client).await; 63 let (access_jwt, _did) = create_account_and_login(&client).await; 64 let payload = json!({ 65 "useCount": 5 66 }); 67 let res = client 68 .post(format!( 69 "{}/xrpc/com.atproto.server.createInviteCode", 70 base_url().await 71 )) 72 .bearer_auth(&access_jwt) 73 .json(&payload) 74 .send() 75 .await 76 .expect("Failed to send request"); 77 assert_eq!(res.status(), StatusCode::FORBIDDEN); 78 let body: Value = res.json().await.expect("Response was not valid JSON"); 79 assert_eq!(body["error"], "AdminRequired"); 80} 81 82#[tokio::test] 83async fn test_create_invite_code_invalid_use_count() { 84 let client = client(); 85 let (access_jwt, _did) = create_admin_account_and_login(&client).await; 86 let payload = json!({ 87 "useCount": 0 88 }); 89 let res = client 90 .post(format!( 91 "{}/xrpc/com.atproto.server.createInviteCode", 92 base_url().await 93 )) 94 .bearer_auth(&access_jwt) 95 .json(&payload) 96 .send() 97 .await 98 .expect("Failed to send request"); 99 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 100 let body: Value = res.json().await.expect("Response was not valid JSON"); 101 assert_eq!(body["error"], "InvalidRequest"); 102} 103 104#[tokio::test] 105async fn test_create_invite_code_for_another_account() { 106 let client = client(); 107 let (access_jwt1, _did1) = create_admin_account_and_login(&client).await; 108 let (_access_jwt2, did2) = create_account_and_login(&client).await; 109 let payload = json!({ 110 "useCount": 3, 111 "forAccount": did2 112 }); 113 let res = client 114 .post(format!( 115 "{}/xrpc/com.atproto.server.createInviteCode", 116 base_url().await 117 )) 118 .bearer_auth(&access_jwt1) 119 .json(&payload) 120 .send() 121 .await 122 .expect("Failed to send request"); 123 assert_eq!(res.status(), StatusCode::OK); 124 let body: Value = res.json().await.expect("Response was not valid JSON"); 125 assert!(body["code"].is_string()); 126} 127 128#[tokio::test] 129async fn test_create_invite_codes_success() { 130 let client = client(); 131 let (access_jwt, did) = create_admin_account_and_login(&client).await; 132 let payload = json!({ 133 "useCount": 2, 134 "codeCount": 3 135 }); 136 let res = client 137 .post(format!( 138 "{}/xrpc/com.atproto.server.createInviteCodes", 139 base_url().await 140 )) 141 .bearer_auth(&access_jwt) 142 .json(&payload) 143 .send() 144 .await 145 .expect("Failed to send request"); 146 assert_eq!(res.status(), StatusCode::OK); 147 let body: Value = res.json().await.expect("Response was not valid JSON"); 148 assert!(body["codes"].is_array()); 149 let codes = body["codes"].as_array().unwrap(); 150 assert_eq!(codes.len(), 1); 151 assert_eq!(codes[0]["account"], did); 152 assert_eq!(codes[0]["codes"].as_array().unwrap().len(), 3); 153} 154 155#[tokio::test] 156async fn test_create_invite_codes_for_multiple_accounts() { 157 let client = client(); 158 let (access_jwt1, did1) = create_admin_account_and_login(&client).await; 159 let (_access_jwt2, did2) = create_account_and_login(&client).await; 160 let payload = json!({ 161 "useCount": 1, 162 "codeCount": 2, 163 "forAccounts": [did1, did2] 164 }); 165 let res = client 166 .post(format!( 167 "{}/xrpc/com.atproto.server.createInviteCodes", 168 base_url().await 169 )) 170 .bearer_auth(&access_jwt1) 171 .json(&payload) 172 .send() 173 .await 174 .expect("Failed to send request"); 175 assert_eq!(res.status(), StatusCode::OK); 176 let body: Value = res.json().await.expect("Response was not valid JSON"); 177 let codes = body["codes"].as_array().unwrap(); 178 assert_eq!(codes.len(), 2); 179 for code_obj in codes { 180 assert!(code_obj["account"].is_string()); 181 assert_eq!(code_obj["codes"].as_array().unwrap().len(), 2); 182 } 183} 184 185#[tokio::test] 186async fn test_create_invite_codes_no_auth() { 187 let client = client(); 188 let payload = json!({ 189 "useCount": 2 190 }); 191 let res = client 192 .post(format!( 193 "{}/xrpc/com.atproto.server.createInviteCodes", 194 base_url().await 195 )) 196 .json(&payload) 197 .send() 198 .await 199 .expect("Failed to send request"); 200 assert_eq!(res.status(), StatusCode::UNAUTHORIZED); 201} 202 203#[tokio::test] 204async fn test_create_invite_codes_non_admin() { 205 let client = client(); 206 let (access_jwt, _did) = create_account_and_login(&client).await; 207 let payload = json!({ 208 "useCount": 2 209 }); 210 let res = client 211 .post(format!( 212 "{}/xrpc/com.atproto.server.createInviteCodes", 213 base_url().await 214 )) 215 .bearer_auth(&access_jwt) 216 .json(&payload) 217 .send() 218 .await 219 .expect("Failed to send request"); 220 assert_eq!(res.status(), StatusCode::FORBIDDEN); 221 let body: Value = res.json().await.expect("Response was not valid JSON"); 222 assert_eq!(body["error"], "AdminRequired"); 223} 224 225#[tokio::test] 226async fn test_get_account_invite_codes_success() { 227 let client = client(); 228 let (admin_jwt, _admin_did) = create_admin_account_and_login(&client).await; 229 let (user_jwt, user_did) = create_account_and_login(&client).await; 230 231 let create_payload = json!({ 232 "useCount": 5, 233 "forAccount": user_did 234 }); 235 let _ = client 236 .post(format!( 237 "{}/xrpc/com.atproto.server.createInviteCode", 238 base_url().await 239 )) 240 .bearer_auth(&admin_jwt) 241 .json(&create_payload) 242 .send() 243 .await 244 .expect("Failed to create invite code"); 245 246 let res = client 247 .get(format!( 248 "{}/xrpc/com.atproto.server.getAccountInviteCodes", 249 base_url().await 250 )) 251 .bearer_auth(&user_jwt) 252 .send() 253 .await 254 .expect("Failed to send request"); 255 assert_eq!(res.status(), StatusCode::OK); 256 let body: Value = res.json().await.expect("Response was not valid JSON"); 257 assert!(body["codes"].is_array()); 258 let codes = body["codes"].as_array().unwrap(); 259 assert!(!codes.is_empty()); 260 let code = &codes[0]; 261 assert!(code["code"].is_string()); 262 assert!(code["available"].is_number()); 263 assert!(code["disabled"].is_boolean()); 264 assert!(code["createdAt"].is_string()); 265 assert!(code["uses"].is_array()); 266 assert_eq!(code["forAccount"], user_did); 267 assert_eq!(code["createdBy"], "admin"); 268} 269 270#[tokio::test] 271async fn test_get_account_invite_codes_no_auth() { 272 let client = client(); 273 let res = client 274 .get(format!( 275 "{}/xrpc/com.atproto.server.getAccountInviteCodes", 276 base_url().await 277 )) 278 .send() 279 .await 280 .expect("Failed to send request"); 281 assert_eq!(res.status(), StatusCode::UNAUTHORIZED); 282} 283 284#[tokio::test] 285async fn test_get_account_invite_codes_include_used_filter() { 286 let client = client(); 287 let (admin_jwt, _admin_did) = create_admin_account_and_login(&client).await; 288 let (user_jwt, user_did) = create_account_and_login(&client).await; 289 290 let create_payload = json!({ 291 "useCount": 5, 292 "forAccount": user_did 293 }); 294 let _ = client 295 .post(format!( 296 "{}/xrpc/com.atproto.server.createInviteCode", 297 base_url().await 298 )) 299 .bearer_auth(&admin_jwt) 300 .json(&create_payload) 301 .send() 302 .await 303 .expect("Failed to create invite code"); 304 305 let res = client 306 .get(format!( 307 "{}/xrpc/com.atproto.server.getAccountInviteCodes", 308 base_url().await 309 )) 310 .bearer_auth(&user_jwt) 311 .query(&[("includeUsed", "false")]) 312 .send() 313 .await 314 .expect("Failed to send request"); 315 assert_eq!(res.status(), StatusCode::OK); 316 let body: Value = res.json().await.expect("Response was not valid JSON"); 317 assert!(body["codes"].is_array()); 318 for code in body["codes"].as_array().unwrap() { 319 assert!(code["available"].as_i64().unwrap() > 0); 320 } 321} 322 323#[tokio::test] 324async fn test_get_account_invite_codes_filters_disabled() { 325 let client = client(); 326 let (admin_jwt, admin_did) = create_admin_account_and_login(&client).await; 327 328 let create_payload = json!({ 329 "useCount": 5, 330 "forAccount": admin_did 331 }); 332 let create_res = client 333 .post(format!( 334 "{}/xrpc/com.atproto.server.createInviteCode", 335 base_url().await 336 )) 337 .bearer_auth(&admin_jwt) 338 .json(&create_payload) 339 .send() 340 .await 341 .expect("Failed to create invite code"); 342 let create_body: Value = create_res.json().await.unwrap(); 343 let code = create_body["code"].as_str().unwrap(); 344 345 let disable_payload = json!({ 346 "codes": [code] 347 }); 348 let _ = client 349 .post(format!( 350 "{}/xrpc/com.atproto.admin.disableInviteCodes", 351 base_url().await 352 )) 353 .bearer_auth(&admin_jwt) 354 .json(&disable_payload) 355 .send() 356 .await 357 .expect("Failed to disable invite code"); 358 359 let res = client 360 .get(format!( 361 "{}/xrpc/com.atproto.server.getAccountInviteCodes", 362 base_url().await 363 )) 364 .bearer_auth(&admin_jwt) 365 .send() 366 .await 367 .expect("Failed to send request"); 368 assert_eq!(res.status(), StatusCode::OK); 369 let body: Value = res.json().await.expect("Response was not valid JSON"); 370 let codes = body["codes"].as_array().unwrap(); 371 for c in codes { 372 assert_ne!( 373 c["code"].as_str().unwrap(), 374 code, 375 "Disabled code should be filtered out" 376 ); 377 } 378}