001package ca.cdr.api.model.json; 002 003/* 004 * #%L 005 * Smile CDR - CDR 006 * %% 007 * Copyright (C) 2016 - 2026 Smile CDR, Inc. 008 * %% 009 * All rights reserved. 010 * #L% 011 */ 012 013import ca.cdr.api.model.enm.PermissionEnum; 014import ca.cdr.api.model.enm.UserTwoFactorAuthEnum; 015import ca.cdr.api.model.json.jackson2deprecated.JsonDateDeserializerJacksonV2Deprecated; 016import ca.cdr.api.model.json.jackson2deprecated.JsonDateSerializerJacksonV2Deprecated; 017import ca.cdr.api.model.json.jackson2deprecated.JsonDateWithEmptyDeserializerJacksonV2Deprecated; 018import ca.uhn.fhir.context.ConfigurationException; 019import ca.uhn.fhir.model.api.IModelJson; 020import com.fasterxml.jackson.annotation.JsonProperty; 021import com.fasterxml.jackson.annotation.JsonPropertyOrder; 022import io.swagger.v3.oas.annotations.Operation; 023import io.swagger.v3.oas.annotations.Parameter; 024import io.swagger.v3.oas.annotations.media.Schema; 025import jakarta.annotation.Nonnull; 026import org.apache.commons.lang3.SerializationUtils; 027import org.apache.commons.lang3.Validate; 028import org.apache.commons.lang3.builder.ToStringBuilder; 029import org.apache.commons.lang3.builder.ToStringStyle; 030import org.hl7.fhir.dstu3.model.DateType; 031import org.springframework.security.core.userdetails.UserDetails; 032import tools.jackson.databind.annotation.JsonDeserialize; 033import tools.jackson.databind.annotation.JsonSerialize; 034 035import java.io.Serializable; 036import java.util.ArrayList; 037import java.util.Collection; 038import java.util.Date; 039import java.util.List; 040import java.util.Optional; 041import java.util.Set; 042import java.util.TreeSet; 043import java.util.stream.Collectors; 044 045import static org.apache.commons.lang3.StringUtils.defaultString; 046import static org.apache.commons.lang3.StringUtils.isNotBlank; 047 048/** 049 * Perhaps if anyone is wondering why we have such a vague fields such as associatedResources and/or defaultLaunchContexts, in our model in the first place. 050 * It's because the SMART spec has this concept of launch contexts, where the launch context is simply the patient/encounter/location that should 051 * be opened when the app starts. 052 * And there's nothing more implied there, just "this is what you should open", so the reason could be anything: 053 * - the user is that patient 054 * - the user has picked that patient from a list 055 * - the user is the parent of the patient 056 * - etc 057 */ 058@Schema(name = "UserDetails", description = "A user definition") 059@JsonPropertyOrder({ 060 "pid", 061 "nodeId", 062 "moduleId", 063 "username", 064 "familyName", 065 "givenName", 066 "notes", 067 "lastActive", 068 "lastConnected", 069 "credentialExpiry", 070 "accountLocked", 071 "systemUser", 072 "authorities", 073 "associatedResources", 074 "defaultLaunchContexts" 075}) 076public class UserDetailsJson implements UserDetails, Cloneable, IHasAuthorities, ca.uhn.fhir.model.api.IModelJson { 077 078 private static final long serialVersionUID = 2L; 079 080 /* 081 * ****************************************************************** 082 * Note: If you add properties, add them to the copy constructor too! 083 * ****************************************************************** 084 */ 085 086 @JsonProperty("accountDisabled") 087 @Parameter(description = "Is this account currently disabled?") 088 private Boolean myAccountDisabled; 089 090 @JsonProperty("notes") 091 @Parameter(description = "Any notes regarding this user") 092 private String myNotes; 093 094 @JsonProperty("email") 095 @Parameter(description = "The user email address") 096 private String myEmail; 097 098 @JsonProperty("accountExpiry") 099 @com.fasterxml.jackson.databind.annotation.JsonSerialize(using = JsonDateSerializerJacksonV2Deprecated.class) 100 @JsonSerialize(using = JsonDateSerializer.class) 101 @com.fasterxml.jackson.databind.annotation.JsonDeserialize( 102 using = JsonDateWithEmptyDeserializerJacksonV2Deprecated.class) 103 @JsonDeserialize(using = JsonDateWithEmptyDeserializer.class) 104 @Parameter(description = "The expiry date for the user (if any) or null if the account should not expire") 105 private Date myAccountExpiry; 106 107 @JsonProperty("accountLocked") 108 @Parameter(description = "Is this account currently locked?") 109 private Boolean myAccountLocked; 110 111 @JsonProperty("failedLoginAttempts") 112 @Parameter(description = "Number of consecutive failed login attempts") 113 private int myFailedLoginAttempts; 114 115 @JsonProperty("authorities") 116 @Parameter(description = "Any authorities (permissions) granted to this user") 117 private List<GrantedAuthorityJson> myAuthorities; 118 119 @JsonProperty("associatedResources") 120 @Schema( 121 description = 122 "A collection of \"associated resource\" IDs. Associated resources are FHIR resources with some connection to the given user, such as a Patient or Practitioner resource representing the actual user.", 123 accessMode = Schema.AccessMode.READ_ONLY) 124 private List<AssociatedResourceJson> myAssociatedResources; 125 126 @JsonProperty("credentialExpiry") 127 @com.fasterxml.jackson.databind.annotation.JsonSerialize(using = JsonDateSerializerJacksonV2Deprecated.class) 128 @JsonSerialize(using = JsonDateSerializer.class) 129 @com.fasterxml.jackson.databind.annotation.JsonDeserialize( 130 using = JsonDateWithEmptyDeserializerJacksonV2Deprecated.class) 131 @JsonDeserialize(using = JsonDateWithEmptyDeserializer.class) 132 @Parameter(description = "If set, provides the date that the user credentials will expire") 133 private Date myCredentialExpiry; 134 135 @JsonProperty("familyName") 136 @Parameter(description = "The user's family (last) name") 137 private String myFamilyName; 138 139 @JsonProperty("givenName") 140 @Parameter(description = "The user's given (first) name") 141 private String myGivenName; 142 143 @JsonProperty(value = "lastActive") 144 @com.fasterxml.jackson.databind.annotation.JsonSerialize(using = JsonDateSerializerJacksonV2Deprecated.class) 145 @JsonSerialize(using = JsonDateSerializer.class) 146 @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = JsonDateDeserializerJacksonV2Deprecated.class) 147 @JsonDeserialize(using = JsonDateDeserializer.class) 148 @Schema( 149 accessMode = Schema.AccessMode.READ_ONLY, 150 description = 151 "The date at which the user account was last used. Note that this property is read-only, and is only updated once per day, so it is accurate only to the date.") 152 private Date myLastActive; 153 154 @JsonProperty(value = "lastConnected") 155 @com.fasterxml.jackson.databind.annotation.JsonSerialize(using = JsonDateSerializerJacksonV2Deprecated.class) 156 @JsonSerialize(using = JsonDateSerializer.class) 157 @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = JsonDateDeserializerJacksonV2Deprecated.class) 158 @JsonDeserialize(using = JsonDateDeserializer.class) 159 @Schema( 160 accessMode = Schema.AccessMode.READ_ONLY, 161 description = 162 "The date at which the user last logged in. This property is read-only and is accurate to the minute.") 163 private Date myLastConnected; 164 165 @Schema( 166 accessMode = Schema.AccessMode.READ_ONLY, 167 description = 168 "The module ID associated with this user account. This is the module ID associated with the Inbound Security module that is responsible for authenticating this user.") 169 @JsonProperty("moduleId") 170 private String myModuleId; 171 172 @Schema( 173 accessMode = Schema.AccessMode.READ_ONLY, 174 description = 175 "The node ID associated with this user. This is the master node ID associated with the Inbound Security module that is responsible for authenticating this user.") 176 @JsonProperty("nodeId") 177 private String myNodeId; 178 179 @JsonProperty("password") 180 @Schema( 181 description = 182 "The user password (note that this property will not be populated when sessions are made available to user code)", 183 readOnly = true) 184 private String myPassword; 185 186 @JsonProperty("pid") 187 @Schema(accessMode = Schema.AccessMode.READ_ONLY, description = "The PID (internal ID) for this user") 188 private Long myPid; 189 190 @JsonProperty("username") 191 @Schema(accessMode = Schema.AccessMode.READ_ONLY, description = "The username for this user") 192 private String myUsername; 193 194 @JsonProperty("usernameNamespace") 195 @Schema(accessMode = Schema.AccessMode.READ_ONLY, description = "The username namespace associated with this user") 196 private String myUsernameNamespace; 197 198 @Schema( 199 accessMode = Schema.AccessMode.READ_ONLY, 200 description = 201 "If this is set, the user cannot be renamed or deleted (this property may only be set by the system)") 202 @JsonProperty("systemUser") 203 private boolean mySystemUser; 204 205 @Schema( 206 accessMode = Schema.AccessMode.READ_ONLY, 207 description = 208 "If this value is set, the user is backed by an external user directory (this property may only be set by the system)") 209 @JsonProperty("external") 210 private boolean myExternal; 211 212 @JsonProperty("defaultLaunchContexts") 213 @Schema( 214 accessMode = Schema.AccessMode.READ_ONLY, 215 description = "The SMART launch contexts associated with this account") 216 private List<LaunchContextJson> myDefaultLaunchContexts; 217 218 @JsonProperty("serviceAccount") 219 private Boolean myServiceAccount; 220 221 @JsonProperty("twoFactorAuthStatus") 222 private UserTwoFactorAuthEnum myTwoFactorAuthStatus; 223 224 /** 225 * Constructor 226 */ 227 public UserDetailsJson() { 228 super(); 229 } 230 231 /** 232 * Constructor 233 */ 234 public UserDetailsJson(UserDetailsJson theCopyObject) { 235 this(); 236 237 setPid(theCopyObject.getPid()); 238 239 setUsername(theCopyObject.getUsername()); 240 setUsernameNamespace(theCopyObject.getUsernameNamespace()); 241 setPassword(theCopyObject.getPassword()); 242 243 setNodeId(theCopyObject.getNodeId()); 244 setModuleId(theCopyObject.getModuleId()); 245 246 setFamilyName(theCopyObject.getFamilyName()); 247 setGivenName(theCopyObject.getGivenName()); 248 setEmail(theCopyObject.getEmail()); 249 250 setNotes(theCopyObject.getNotes()); 251 setFailedLoginAttempts(theCopyObject.getFailedLoginAttempts()); 252 setAccountExpiry(theCopyObject.getAccountExpiry()); 253 setAccountDisabled(theCopyObject.isAccountDisabled()); 254 setAccountLocked(theCopyObject.isAccountLocked()); 255 setServiceAccount(theCopyObject.isServiceAccount()); 256 setSystemUser(theCopyObject.isSystemUser()); 257 setCredentialExpiry(theCopyObject.getCredentialExpiry()); 258 setLastActive(theCopyObject.getLastActive()); 259 setLastConnected(theCopyObject.getLastConnected()); 260 261 setAuthorities(theCopyObject.getAuthorities()); 262 setExternal(theCopyObject.isExternal()); 263 264 setTwoFactorAuthStatus(theCopyObject.getTwoFactorAuthStatus()); 265 266 getDefaultLaunchContexts().addAll(theCopyObject.getDefaultLaunchContexts()); 267 getAssociatedResources().addAll(theCopyObject.getAssociatedResources()); 268 } 269 270 /* 271 * ****************************************************************** 272 * Note: If you add properties, add them to the copy constructor too! 273 * ****************************************************************** 274 */ 275 276 public UserTwoFactorAuthEnum getTwoFactorAuthStatus() { 277 return myTwoFactorAuthStatus; 278 } 279 280 public UserDetailsJson setTwoFactorAuthStatus(UserTwoFactorAuthEnum theTwoFactorAuthStatus) { 281 myTwoFactorAuthStatus = theTwoFactorAuthStatus; 282 return this; 283 } 284 285 public void addAssociatedResource(String theType, String theResourceId) { 286 Validate.notBlank(theType, "The type must not be null"); 287 AssociatedResourceTypeEnum type; 288 try { 289 type = AssociatedResourceTypeEnum.valueOf(theType); 290 } catch (Exception e) { 291 throw new ConfigurationException("Invalid type: " + theType); 292 } 293 addAssociatedResource(type, theResourceId); 294 } 295 296 public void addAssociatedResource(AssociatedResourceTypeEnum theType, String theResourceId) { 297 Validate.notNull(theType, "The type must not be null"); 298 Validate.notBlank(theResourceId, "The resource ID must not be null"); 299 300 getAssociatedResources() 301 .add(new AssociatedResourceJson() 302 .setType(AssociatedResourceTypeEnum.SELF) 303 .setResourceId(theResourceId)); 304 } 305 306 public void addAuthorities(GrantedAuthorityJson... theAuthority) { 307 for (GrantedAuthorityJson next : theAuthority) { 308 addAuthority(next); 309 } 310 } 311 312 public UserDetailsJson addAuthority(PermissionEnum thePermission) { 313 getAuthorities().add(new GrantedAuthorityJson(thePermission)); 314 return this; 315 } 316 317 public void addAuthority(GrantedAuthorityJson theAuthority) { 318 Validate.notNull(theAuthority, "theAuthority must not be null"); 319 getAuthorities().add(theAuthority); 320 } 321 322 public LaunchContextJson addDefaultLaunchContext() { 323 LaunchContextJson ctx = new LaunchContextJson(); 324 getDefaultLaunchContexts().add(ctx); 325 return ctx; 326 } 327 328 @SuppressWarnings("MethodDoesntCallSuperMethod") 329 @Override 330 public UserDetailsJson clone() { 331 return SerializationUtils.clone(this); 332 } 333 334 public Date getAccountExpiry() { 335 return myAccountExpiry; 336 } 337 338 public void setAccountExpiry(Date theAccountExpiry) { 339 myAccountExpiry = theAccountExpiry; 340 } 341 342 public boolean hasAccountExpiryDate() { 343 return myAccountExpiry != null; 344 } 345 346 public String getAccountExpiryDateAsIsoString() { 347 if (myAccountExpiry == null) { 348 return ""; 349 } 350 return new DateType(myAccountExpiry).getValueAsString(); 351 } 352 353 public List<AssociatedResourceJson> getAssociatedResources() { 354 if (myAssociatedResources == null) { 355 myAssociatedResources = new ArrayList<>(); 356 } 357 return myAssociatedResources; 358 } 359 360 public boolean hasAuthorities() { 361 return myAuthorities != null; 362 } 363 364 @Override 365 @Nonnull 366 public List<GrantedAuthorityJson> getAuthorities() { 367 if (myAuthorities == null) { 368 myAuthorities = new ArrayList<>(); 369 } 370 return myAuthorities; 371 } 372 373 public UserDetailsJson setAuthorities(Collection<GrantedAuthorityJson> theAuthorities) { 374 myAuthorities = new ArrayList<>(theAuthorities); 375 return this; 376 } 377 378 public boolean hasCredentialExpiryDate() { 379 return myCredentialExpiry != null; 380 } 381 382 public Date getCredentialExpiry() { 383 return myCredentialExpiry; 384 } 385 386 public void setCredentialExpiry(Date theCredentialExpiry) { 387 myCredentialExpiry = theCredentialExpiry; 388 } 389 390 public String getCredentialExpiryDateAsIsoString() { 391 if (myCredentialExpiry == null) { 392 return ""; 393 } 394 return new DateType(myCredentialExpiry).getValueAsString(); 395 } 396 397 public boolean hasDefaultLaunchContexts() { 398 return myDefaultLaunchContexts != null; 399 } 400 401 public List<LaunchContextJson> getDefaultLaunchContexts() { 402 if (myDefaultLaunchContexts == null) { 403 myDefaultLaunchContexts = new ArrayList<>(); 404 } 405 return myDefaultLaunchContexts; 406 } 407 408 public Optional<String> getDefaultLaunchContextResourceIdForContextType(@Nonnull String theContextType) { 409 for (LaunchContextJson contextParam : getDefaultLaunchContexts()) { 410 if (theContextType.equalsIgnoreCase(contextParam.getContextType())) { 411 return Optional.of(contextParam.getResourceId()); 412 } 413 } 414 415 return Optional.empty(); 416 } 417 418 @SuppressWarnings("unused") 419 public String getDefaultLaunchContextsCommaSeparated(String theType) { 420 StringBuilder b = new StringBuilder(); 421 getDefaultLaunchContexts().stream() 422 .filter(t -> t.getContextType().equals(theType)) 423 .filter(t -> isNotBlank(t.getResourceId())) 424 .forEach(t -> { 425 if (!b.isEmpty()) { 426 b.append(", "); 427 } 428 b.append(t.getResourceId()); 429 }); 430 return b.toString(); 431 } 432 433 public boolean hasEmail() { 434 return myEmail != null; 435 } 436 437 public String getEmail() { 438 return myEmail; 439 } 440 441 public UserDetailsJson setEmail(String theEmail) { 442 myEmail = theEmail; 443 return this; 444 } 445 446 public boolean hasFamilyName() { 447 return myFamilyName != null; 448 } 449 450 public String getFamilyName() { 451 return myFamilyName; 452 } 453 454 public UserDetailsJson setFamilyName(String theFamilyName) { 455 myFamilyName = theFamilyName; 456 return this; 457 } 458 459 public String getFullName() { 460 return (defaultString(myGivenName) + ' ' + defaultString(myFamilyName)).trim(); 461 } 462 463 public boolean hasGivenName() { 464 return myGivenName != null; 465 } 466 467 public String getGivenName() { 468 return myGivenName; 469 } 470 471 public UserDetailsJson setGivenName(String theGivenName) { 472 myGivenName = theGivenName; 473 return this; 474 } 475 476 public Date getLastActive() { 477 return myLastActive; 478 } 479 480 public void setLastActive(Date theLastActive) { 481 myLastActive = theLastActive; 482 } 483 484 public Date getLastConnected() { 485 return myLastConnected; 486 } 487 488 public void setLastConnected(Date theLastConnected) { 489 myLastConnected = theLastConnected; 490 } 491 492 public String getModuleId() { 493 return myModuleId; 494 } 495 496 public UserDetailsJson setModuleId(String theModuleId) { 497 myModuleId = theModuleId; 498 return this; 499 } 500 501 public String getNodeId() { 502 return myNodeId; 503 } 504 505 public UserDetailsJson setNodeId(String theNodeId) { 506 myNodeId = theNodeId; 507 return this; 508 } 509 510 public boolean hasNotes() { 511 return myNotes != null; 512 } 513 514 public String getNotes() { 515 return myNotes; 516 } 517 518 public void setNotes(String theNotes) { 519 myNotes = theNotes; 520 } 521 522 @Override 523 public String getPassword() { 524 return myPassword; 525 } 526 527 public UserDetailsJson setPassword(String thePassword) { 528 myPassword = thePassword; 529 return this; 530 } 531 532 public boolean hasPassword() { 533 return myPassword != null; 534 } 535 536 public Long getPid() { 537 return myPid; 538 } 539 540 public UserDetailsJson setPid(Long thePid) { 541 myPid = thePid; 542 return this; 543 } 544 545 public Set<String> getAuthorityNames() { 546 return getAuthorities().stream() 547 .map(t -> t.getPermission().name()) 548 .collect(Collectors.toCollection(TreeSet::new)); 549 } 550 551 public Boolean getServiceUser() { 552 if (myServiceAccount == null) { 553 return false; 554 } 555 return myServiceAccount; 556 } 557 558 public boolean hasUsername() { 559 return myUsername != null; 560 } 561 562 @Override 563 public String getUsername() { 564 return myUsername; 565 } 566 567 public UserDetailsJson setUsername(String theUsername) { 568 myUsername = theUsername; 569 return this; 570 } 571 572 @Override 573 public List<GrantedAuthorityJson> getPermissions() { 574 return getAuthorities(); 575 } 576 577 @Operation(summary = "hasAuthority", description = "Does the user have the given permission?") 578 public boolean hasAuthority( 579 @Parameter(name = "thePermission", description = "The name of the permission, e.g. 'ROLE_FHIR_CLIENT'") 580 String thePermission) { 581 for (GrantedAuthorityJson next : getAuthorities()) { 582 if (next.getPermission().name().equals(thePermission)) { 583 return true; 584 } 585 } 586 return false; 587 } 588 589 public boolean hasAccountDisabled() { 590 return myAccountDisabled != null; 591 } 592 593 public boolean isAccountDisabled() { 594 if (myAccountDisabled == null) { 595 return false; 596 } 597 return myAccountDisabled; 598 } 599 600 public void setAccountDisabled(boolean theAccountDisabled) { 601 myAccountDisabled = theAccountDisabled; 602 } 603 604 public boolean hasAccountLocked() { 605 return myAccountLocked != null; 606 } 607 608 public boolean isAccountLocked() { 609 if (myAccountLocked == null) { 610 return false; 611 } 612 return myAccountLocked; 613 } 614 615 public void lockAccount() { 616 setAccountLocked(true); 617 } 618 619 public void setAccountLocked(boolean theAccountLocked) { 620 myAccountLocked = theAccountLocked; 621 } 622 623 public void setFailedLoginAttempts(int theFailedLoginAttempts) { 624 myFailedLoginAttempts = theFailedLoginAttempts; 625 } 626 627 public int getFailedLoginAttempts() { 628 return myFailedLoginAttempts; 629 } 630 631 public int incrementFailedLoginAttempts() { 632 setFailedLoginAttempts(getFailedLoginAttempts() + 1); 633 return getFailedLoginAttempts(); 634 } 635 636 public void resetFailedLoginAttempts() { 637 setFailedLoginAttempts(0); 638 } 639 640 @Override 641 public boolean isAccountNonExpired() { 642 return myAccountExpiry == null || myAccountExpiry.getTime() > System.currentTimeMillis(); 643 } 644 645 @Override 646 public boolean isAccountNonLocked() { 647 return !isAccountLocked(); 648 } 649 650 @Override 651 public boolean isCredentialsNonExpired() { 652 return myCredentialExpiry == null || myCredentialExpiry.getTime() > System.currentTimeMillis(); 653 } 654 655 @Override 656 public boolean isEnabled() { 657 return !isAccountDisabled(); 658 } 659 660 public boolean isExternal() { 661 return myExternal; 662 } 663 664 public void setExternal(boolean theExternal) { 665 myExternal = theExternal; 666 } 667 668 public boolean hasServiceAccount() { 669 return myServiceAccount != null; 670 } 671 672 public boolean isServiceAccount() { 673 if (myServiceAccount == null) { 674 return false; 675 } 676 return myServiceAccount; 677 } 678 679 public void setServiceAccount(boolean theServiceAccount) { 680 myServiceAccount = theServiceAccount; 681 } 682 683 public boolean isSystemUser() { 684 return mySystemUser; 685 } 686 687 public UserDetailsJson setSystemUser(boolean theSystemUser) { 688 mySystemUser = theSystemUser; 689 return this; 690 } 691 692 @Override 693 public String toString() { 694 ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.NO_CLASS_NAME_STYLE); 695 b.append("pid", myPid); 696 b.append("username", myUsername); 697 b.append("familyName", myFamilyName); 698 b.append("givenName", myGivenName); 699 b.append("authorities", myAuthorities); 700 b.append("lastActive", myLastActive); 701 b.append("lastConnected", myLastConnected); 702 b.append("failedLoginAttempts", myFailedLoginAttempts); 703 if (myAccountDisabled != null && myAccountDisabled) { 704 b.append("accountDisabled", myAccountDisabled); 705 } 706 if (myAccountExpiry != null) { 707 b.append("accountExpiryDate", myAccountExpiry); 708 } 709 if (myAccountLocked != null && myAccountLocked) { 710 b.append("accountLocked", myAccountLocked); 711 } 712 if (myCredentialExpiry != null) { 713 b.append("credentialExpiryDate", myCredentialExpiry); 714 } 715 if (mySystemUser) { 716 b.append("systemUser", mySystemUser); 717 } 718 if (myExternal) { 719 b.append("external", myExternal); 720 } 721 b.append("nodeId", myNodeId); 722 b.append("moduleId", myModuleId); 723 return b.toString(); 724 } 725 726 public String getUsernameNamespace() { 727 return myUsernameNamespace; 728 } 729 730 public void setUsernameNamespace(String theUsernameNamespace) { 731 myUsernameNamespace = theUsernameNamespace; 732 } 733 734 public boolean hasUsernameNamespace() { 735 return myUsernameNamespace != null; 736 } 737 738 @Operation( 739 summary = "getOrCreateDefaultLaunchContext", 740 description = "Returns the first default launch context for the given type, creating one if none exists") 741 public LaunchContextJson getOrCreateDefaultLaunchContext( 742 @Parameter(name = "theContextType", description = "The context type, e.g. \"patient\" or \"practitioner\"") 743 String theContextType) { 744 for (LaunchContextJson next : getDefaultLaunchContexts()) { 745 if (next.getContextType().equals(theContextType)) { 746 return next; 747 } 748 } 749 750 LaunchContextJson retVal = new LaunchContextJson().setContextType(theContextType); 751 getDefaultLaunchContexts().add(retVal); 752 return retVal; 753 } 754 755 @Operation( 756 summary = "getOrCreateDefaultLaunchContext", 757 description = "Returns the first default launch context for the given type, creating one if none exists") 758 public LaunchContextJson getOrCreateDefaultLaunchContext( 759 @Parameter(name = "theContextType", description = "The context type, e.g. \"patient\" or \"practitioner\"") 760 String theContextType, 761 @Parameter(name = "theIndex", description = "The index, starting at 0") int theIndex) { 762 763 int foundIndex = 0; 764 for (LaunchContextJson next : getDefaultLaunchContexts()) { 765 if (next.getContextType().equals(theContextType)) { 766 if (theIndex == foundIndex) { 767 return next; 768 } else { 769 foundIndex++; 770 } 771 } 772 } 773 774 LaunchContextJson retVal = new LaunchContextJson().setContextType(theContextType); 775 getDefaultLaunchContexts().add(retVal); 776 return retVal; 777 } 778 779 /** 780 * What type of relationship does the user have to the 781 * given resource 782 */ 783 public enum AssociatedResourceTypeEnum { 784 785 /** 786 * This associated resource is the user themself 787 */ 788 SELF 789 } 790 791 /** 792 * This structure represents a link between a user in the auth database 793 * and a resource in the FHIR database. This can be used, for example, 794 * to specify that a particular user is a specific Patient in the 795 * CDR. That linkage can then be applied in order to make 796 * security/permission decisions. 797 */ 798 @Schema( 799 name = "AssociatedResource", 800 description = "This structure represents a link between a user in the auth database " 801 + "and a resource in the FHIR database. This can be used, for example, " 802 + "to specify that a particular user is a specific Patient in the " 803 + "CDR. That linkage can then be applied in order to make " 804 + "security/permission decisions.") 805 public static class AssociatedResourceJson implements Serializable, IModelJson { 806 807 @JsonProperty("type") 808 @Schema(description = "The relationship between the user and the resource") 809 private AssociatedResourceTypeEnum myType; 810 811 @JsonProperty("resourceId") 812 @Schema(description = "The resource ID itself, e.g. 'Patient/123'", example = "Patient/123") 813 private String myResourceId; 814 815 public String getResourceId() { 816 return myResourceId; 817 } 818 819 public AssociatedResourceJson setResourceId(String theResourceId) { 820 myResourceId = theResourceId; 821 return this; 822 } 823 824 public AssociatedResourceTypeEnum getType() { 825 return myType; 826 } 827 828 public AssociatedResourceJson setType(String theType) { 829 myType = AssociatedResourceTypeEnum.valueOf(theType); 830 return this; 831 } 832 833 public AssociatedResourceJson setType(AssociatedResourceTypeEnum theType) { 834 myType = theType; 835 return this; 836 } 837 } 838 839 public static PermissionEnum toPermissionEnum(String thePermission) { 840 try { 841 return PermissionEnum.valueOf(thePermission); 842 } catch (Exception e) { 843 throw new ConfigurationException("Invalid permission name: " + thePermission); 844 } 845 } 846}