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