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