001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.file; 029 030import org.opencms.db.CmsUserSettings; 031import org.opencms.main.CmsException; 032import org.opencms.main.CmsIllegalArgumentException; 033import org.opencms.main.OpenCms; 034import org.opencms.security.CmsPrincipal; 035import org.opencms.security.CmsSecurityException; 036import org.opencms.security.I_CmsPrincipal; 037import org.opencms.util.CmsMacroResolver; 038import org.opencms.util.CmsStringUtil; 039import org.opencms.util.CmsUUID; 040 041import java.util.Collections; 042import java.util.HashMap; 043import java.util.Locale; 044import java.util.Map; 045import java.util.Objects; 046 047/** 048 * A user principal in the OpenCms permission system.<p> 049 * 050 * A user in OpenCms is uniquely defined by its user named returned by 051 * <code>{@link #getName()}</code>.<p> 052 * 053 * Basic users in OpenCms are users that can access the OpenCms Workplace. 054 * Moreover, the user must be created by another user with the 055 * <code>{@link org.opencms.security.CmsRole#ACCOUNT_MANAGER}</code> role. 056 * These users are "content managers" that actually have write permissions in 057 * at last some parts of the VFS.<p> 058 * 059 * Another possibility is to have users in a 'Guests' group. 060 * These users do not have access to the OpenCms Workplace. 061 * However, an user in a 'Guests' group can be created by every user, for example 062 * the "Guest" user. The main use case is that these users are used for users of 063 * the website that can generate their own accounts, in a "please register your 064 * account..." scenario. 065 * These user accounts can then be used to build personalized web sites.<p> 066 * 067 * @since 6.0.0 068 * 069 * @see CmsGroup 070 */ 071public class CmsUser extends CmsPrincipal implements Cloneable { 072 073 /** Flag indicating changed additional infos. */ 074 public static final int FLAG_ADDITIONAL_INFOS = 4; 075 076 /** Flag indicating changed core data. */ 077 public static final int FLAG_CORE_DATA = 8; 078 079 /** Flag indicating a changed last login date. */ 080 public static final int FLAG_LAST_LOGIN = 2; 081 082 /** The serial version id. */ 083 private static final long serialVersionUID = 4812858003805477345L; 084 085 /** Storage for additional user information. */ 086 private Map<String, Object> m_additionalInfo; 087 088 /** The creation date. */ 089 private long m_dateCreated; 090 091 /** The email of the user. */ 092 private String m_email; 093 094 /** The first name of this user. */ 095 private String m_firstname; 096 097 /** Boolean flag whether the last-login time stamp of this user was modified. */ 098 private boolean m_isTouched; 099 100 /** The last login date of this user. */ 101 private long m_lastlogin; 102 103 /** The last name of this user. */ 104 private String m_lastname; 105 106 /** The password of this user. */ 107 private String m_password; 108 109 /** 110 * Creates a new, empty OpenCms user principal.<p> 111 * 112 * Mostly intended to be used with the <code>org.opencms.workplace.tools.accounts.A_CmsEditUserDialog</code>.<p> 113 */ 114 public CmsUser() { 115 116 this( 117 null, 118 "", 119 "", 120 "", 121 "", 122 "", 123 0, 124 I_CmsPrincipal.FLAG_ENABLED, 125 System.currentTimeMillis(), 126 Collections.singletonMap(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION, (Object)"")); 127 } 128 129 /** 130 * Creates a new OpenCms user principal.<p> 131 * 132 * @param id the unique id of the new user 133 * @param name the fully qualified name of the new user 134 * @param password the password of the user 135 * @param firstname the first name 136 * @param lastname the last name 137 * @param email the email address 138 * @param lastlogin time stamp 139 * @param flags flags 140 * @param dateCreated the creation date 141 * @param additionalInfo user related information 142 */ 143 public CmsUser( 144 CmsUUID id, 145 String name, 146 String password, 147 String firstname, 148 String lastname, 149 String email, 150 long lastlogin, 151 int flags, 152 long dateCreated, 153 Map<String, Object> additionalInfo) { 154 155 m_id = id; 156 m_name = name; 157 m_password = password; 158 m_firstname = firstname; 159 m_lastname = lastname; 160 m_email = email; 161 m_lastlogin = lastlogin; 162 m_flags = flags; 163 m_dateCreated = dateCreated; 164 if (additionalInfo != null) { 165 m_additionalInfo = new HashMap<String, Object>(additionalInfo); 166 } else { 167 m_additionalInfo = new HashMap<String, Object>(); 168 } 169 if (m_additionalInfo.get(CmsUserSettings.ADDITIONAL_INFO_ADDRESS) == null) { 170 m_additionalInfo.put(CmsUserSettings.ADDITIONAL_INFO_ADDRESS, ""); 171 } 172 if (m_additionalInfo.get(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION) == null) { 173 m_additionalInfo.put(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION, ""); 174 } 175 } 176 177 /** 178 * Validates an email address.<p> 179 * 180 * That means, the parameter should only be composed by digits and standard english letters, points, underscores and exact one "At" symbol.<p> 181 * 182 * @param email the email to validate 183 */ 184 public static void checkEmail(String email) { 185 186 OpenCms.getValidationHandler().checkEmail(email); 187 } 188 189 /** 190 * Validates a zip code.<p> 191 * 192 * That means, the parameter should only be composed by digits and standard english letters.<p> 193 * 194 * @param zipcode the zip code to validate 195 */ 196 public static void checkZipCode(String zipcode) { 197 198 OpenCms.getValidationHandler().checkZipCode(zipcode); 199 } 200 201 /** 202 * Returns the "full" name of the given user in the format <code>"{firstname} {lastname} ({username})"</code>, 203 * or the empty String <code>""</code> if the user is null.<p> 204 * 205 * @param user the user to get the full name from 206 * @return the "full" name the user 207 * 208 * @see #getFullName() 209 */ 210 public static String getFullName(CmsUser user) { 211 212 if (user == null) { 213 return ""; 214 } else { 215 return user.getFullName(); 216 } 217 } 218 219 /** 220 * Checks whether the flag indicates additional info changes.<p> 221 * 222 * @param changes the changes flags 223 * 224 * @return <code>true</code> in case the additional infos changed 225 */ 226 public static boolean hasChangedAdditionalInfos(int changes) { 227 228 return (changes & FLAG_ADDITIONAL_INFOS) == FLAG_ADDITIONAL_INFOS; 229 } 230 231 /** 232 * Checks whether the flag indicates core data changes.<p> 233 * 234 * @param changes the changes flags 235 * 236 * @return <code>true</code> in case the core data changed 237 */ 238 public static boolean hasChangedCoreData(int changes) { 239 240 return (changes & FLAG_CORE_DATA) == FLAG_CORE_DATA; 241 } 242 243 /** 244 * Checks whether the flag indicates last login date changes.<p> 245 * 246 * @param changes the changes flags 247 * 248 * @return <code>true</code> in case the last login date changed 249 */ 250 public static boolean hasChangedLastLogin(int changes) { 251 252 return (changes & FLAG_LAST_LOGIN) == FLAG_LAST_LOGIN; 253 } 254 255 /** 256 * Checks if the given String starts with {@link I_CmsPrincipal#PRINCIPAL_USER} followed by a dot.<p> 257 * 258 * <ul> 259 * <li>Works if the given String is <code>null</code>. 260 * <li>Removes white spaces around the String before the check. 261 * <li>Also works with prefixes not being in upper case. 262 * <li>Does not check if the user after the prefix actually exists. 263 * </ul> 264 * 265 * @param principalName the user name to check 266 * 267 * @return <code>true</code> in case the String starts with {@link I_CmsPrincipal#PRINCIPAL_USER} followed by a dot 268 */ 269 public static boolean hasPrefix(String principalName) { 270 271 return CmsStringUtil.isNotEmptyOrWhitespaceOnly(principalName) 272 && (principalName.trim().toUpperCase().startsWith(I_CmsPrincipal.PRINCIPAL_USER + ".")); 273 } 274 275 /** 276 * Removes the prefix if the given String starts with {@link I_CmsPrincipal#PRINCIPAL_USER} followed by a dot.<p> 277 * 278 * <ul> 279 * <li>Works if the given String is <code>null</code>. 280 * <li>If the given String does not start with {@link I_CmsPrincipal#PRINCIPAL_USER} followed by a dot it is returned unchanged. 281 * <li>Removes white spaces around the user name. 282 * <li>Also works with prefixes not being in upper case. 283 * <li>Does not check if the user after the prefix actually exists. 284 * </ul> 285 * 286 * @param principalName the user name to remove the prefix from 287 * 288 * @return the given String with the prefix {@link I_CmsPrincipal#PRINCIPAL_USER} and the following dot removed 289 */ 290 public static String removePrefix(String principalName) { 291 292 String result = principalName; 293 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(principalName)) { 294 if (hasPrefix(principalName)) { 295 result = principalName.trim().substring(I_CmsPrincipal.PRINCIPAL_USER.length() + 1); 296 } 297 } 298 return result; 299 } 300 301 /** 302 * Checks if the provided user name is a valid user name and can be used as an argument value 303 * for {@link #setName(String)}.<p> 304 * 305 * @param name the user name to check 306 * 307 * @throws CmsIllegalArgumentException if the check fails 308 */ 309 public void checkName(String name) throws CmsIllegalArgumentException { 310 311 OpenCms.getValidationHandler().checkUserName(name); 312 } 313 314 /** 315 * @see java.lang.Object#clone() 316 */ 317 @Override 318 public CmsUser clone() { 319 320 return new CmsUser( 321 m_id, 322 m_name, 323 m_password, 324 m_firstname, 325 m_lastname, 326 m_email, 327 m_lastlogin, 328 m_flags, 329 m_dateCreated, 330 new HashMap<String, Object>(m_additionalInfo)); 331 } 332 333 /** 334 * Deletes a value from this users "additional information" storage map.<p> 335 * 336 * @param key the additional user information to delete 337 * 338 * @see #getAdditionalInfo() 339 */ 340 public void deleteAdditionalInfo(String key) { 341 342 m_additionalInfo.remove(key); 343 } 344 345 /** 346 * Returns this users complete "additional information" storage map.<p> 347 * 348 * The "additional information" storage map is a simple {@link java.util.Map} 349 * that can be used to store any key / value pairs for the user. 350 * Some information parts of the users address are stored in this map 351 * by default.<p> 352 * 353 * @return this users complete "additional information" storage map 354 */ 355 public Map<String, Object> getAdditionalInfo() { 356 357 return m_additionalInfo; 358 } 359 360 /** 361 * Returns a value from this users "additional information" storage map, 362 * or <code>null</code> if no value for the given key is available.<p> 363 * 364 * @param key selects the value to return from the "additional information" storage map 365 * 366 * @return the selected value from this users "additional information" storage map 367 * 368 * @see #getAdditionalInfo() 369 */ 370 public Object getAdditionalInfo(String key) { 371 372 return m_additionalInfo.get(key); 373 } 374 375 /** 376 * Returns the address line of this user.<p> 377 * 378 * @return the address line of this user 379 */ 380 public String getAddress() { 381 382 return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_ADDRESS); 383 } 384 385 /** 386 * Returns the changes of this user compared to the previous user data.<p> 387 * 388 * @param oldUser the old user 389 * 390 * @return the changes flags 391 */ 392 public int getChanges(CmsUser oldUser) { 393 394 int result = 0; 395 if (oldUser.m_lastlogin != m_lastlogin) { 396 result = result | FLAG_LAST_LOGIN; 397 } 398 if (!oldUser.m_additionalInfo.equals(m_additionalInfo)) { 399 result = result | FLAG_ADDITIONAL_INFOS; 400 } 401 if (!Objects.equals(oldUser.m_email, m_email) 402 || !Objects.equals(oldUser.m_description, m_description) 403 || !Objects.equals(oldUser.m_firstname, m_firstname) 404 || !Objects.equals(oldUser.m_lastname, m_lastname) 405 || !Objects.equals(oldUser.m_password, m_password) 406 || (oldUser.m_flags != m_flags)) { 407 result = result | FLAG_CORE_DATA; 408 } 409 return result; 410 } 411 412 /** 413 * Returns the city information of this user.<p> 414 * 415 * This information is stored in the "additional information" storage map 416 * using the key <code>{@link CmsUserSettings#ADDITIONAL_INFO_CITY}</code>.<p> 417 * 418 * @return the city information of this user 419 */ 420 public String getCity() { 421 422 return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_CITY); 423 } 424 425 /** 426 * Returns the country information of this user.<p> 427 * 428 * This information is stored in the "additional information" storage map 429 * using the key <code>{@link CmsUserSettings#ADDITIONAL_INFO_COUNTRY}</code>.<p> 430 * 431 * @return the country information of this user 432 */ 433 public String getCountry() { 434 435 return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_COUNTRY); 436 } 437 438 /** 439 * Returns the creation date.<p> 440 * 441 * @return the creation date 442 */ 443 public long getDateCreated() { 444 445 return m_dateCreated; 446 } 447 448 /** 449 * @see org.opencms.security.CmsPrincipal#getDescription() 450 */ 451 @Override 452 public String getDescription() { 453 454 return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION); 455 } 456 457 /** 458 * Returns the description of this organizational unit.<p> 459 * 460 * @param locale the locale 461 * 462 * @return the description of this organizational unit 463 */ 464 public String getDescription(Locale locale) { 465 466 CmsMacroResolver macroResolver = new CmsMacroResolver(); 467 macroResolver.setMessages(org.opencms.db.generic.Messages.get().getBundle(locale)); 468 return macroResolver.resolveMacros((String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION)); 469 } 470 471 /** 472 * @see org.opencms.security.CmsPrincipal#getDisplayName(org.opencms.file.CmsObject, java.util.Locale) 473 */ 474 @Override 475 public String getDisplayName(CmsObject cms, Locale locale) throws CmsException { 476 477 if (OpenCms.getOrgUnitManager().getOrganizationalUnits(cms, "", true).size() > 0) { 478 return org.opencms.security.Messages.get().getBundle(locale).key( 479 org.opencms.security.Messages.GUI_PRINCIPAL_DISPLAY_NAME_2, 480 getFullName(), 481 OpenCms.getOrgUnitManager().readOrganizationalUnit(cms, getOuFqn()).getDisplayName(locale)); 482 } else { 483 return getFullName(); 484 } 485 } 486 487 /** 488 * Returns the email address of this user.<p> 489 * 490 * @return the email address of this user 491 */ 492 public String getEmail() { 493 494 return m_email; 495 } 496 497 /** 498 * Returns the first name of this user.<p> 499 * 500 * @return the first name of this user 501 */ 502 public String getFirstname() { 503 504 return m_firstname; 505 } 506 507 /** 508 * Returns the "full" name of the this user in the format <code>"{firstname} {lastname} ({username})"</code>.<p> 509 * 510 * @return the "full" name this user 511 */ 512 public String getFullName() { 513 514 StringBuffer buf = new StringBuffer(); 515 String first = getFirstname(); 516 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(first)) { 517 buf.append(first); 518 buf.append(" "); 519 } 520 String last = getLastname(); 521 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(last)) { 522 buf.append(last); 523 buf.append(" "); 524 } 525 buf.append("("); 526 buf.append(getSimpleName()); 527 buf.append(")"); 528 return buf.toString(); 529 } 530 531 /** 532 * Returns the institution information of this user.<p> 533 * 534 * This information is stored in the "additional information" storage map 535 * using the key <code>{@link CmsUserSettings#ADDITIONAL_INFO_INSTITUTION}</code>.<p> 536 * 537 * @return the institution information of this user 538 */ 539 public String getInstitution() { 540 541 return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_INSTITUTION); 542 } 543 544 /** 545 * Returns the time of the last login of this user.<p> 546 * 547 * @return the time of the last login of this user 548 */ 549 public long getLastlogin() { 550 551 return m_lastlogin; 552 } 553 554 /** 555 * Returns the last name of this user.<p> 556 * 557 * @return the last name of this user 558 */ 559 public String getLastname() { 560 561 return m_lastname; 562 } 563 564 /** 565 * Returns the encrypted user password.<p> 566 * 567 * @return the encrypted user password 568 */ 569 public String getPassword() { 570 571 return m_password; 572 } 573 574 /** 575 * Returns the zip code information of this user.<p> 576 * 577 * This information is stored in the "additional information" storage map 578 * using the key <code>{@link CmsUserSettings#ADDITIONAL_INFO_ZIPCODE}</code>.<p> 579 * 580 * @return the zip code information of this user 581 */ 582 public String getZipcode() { 583 584 return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_ZIPCODE); 585 } 586 587 /** 588 * @see org.opencms.security.I_CmsPrincipal#isGroup() 589 */ 590 @Override 591 public boolean isGroup() { 592 593 return false; 594 } 595 596 /** 597 * Checks if this user is the default guest user.<p> 598 * 599 * @return <code>true</code> if this user is the default guest user 600 */ 601 public boolean isGuestUser() { 602 603 return OpenCms.getDefaultUsers().isUserGuest(getName()); 604 } 605 606 /** 607 * Returns <code>true</code> if this user is not able to manage itself.<p> 608 * 609 * @return <code>true</code> if this user is not able to manage itself 610 */ 611 public boolean isManaged() { 612 613 return (getFlags() & I_CmsPrincipal.FLAG_USER_MANAGED) == I_CmsPrincipal.FLAG_USER_MANAGED; 614 } 615 616 /** 617 * Returns <code>true</code> if this user was touched.<p> 618 * 619 * @return boolean true if this user was touched 620 */ 621 public boolean isTouched() { 622 623 return m_isTouched; 624 } 625 626 /** 627 * @see org.opencms.security.I_CmsPrincipal#isUser() 628 */ 629 @Override 630 public boolean isUser() { 631 632 return true; 633 } 634 635 /** 636 * Checks if the user is marked as webuser.<p> 637 * 638 * @return <code>true</code> if the user is marked as webuser 639 */ 640 public boolean isWebuser() { 641 642 return (getFlags() & FLAG_USER_WEBUSER) == FLAG_USER_WEBUSER; 643 } 644 645 /** 646 * Sets this users complete "additional information" storage map to the given value.<p> 647 * 648 * @param additionalInfo the complete "additional information" map to set 649 * 650 * @see #getAdditionalInfo() 651 */ 652 public void setAdditionalInfo(Map<String, Object> additionalInfo) { 653 654 m_additionalInfo = additionalInfo; 655 } 656 657 /** 658 * Stores a value in this users "additional information" storage map with the given access key.<p> 659 * 660 * @param key the key to store the value under 661 * @param value the value to store in the users "additional information" storage map 662 * 663 * @see #getAdditionalInfo() 664 */ 665 public void setAdditionalInfo(String key, Object value) { 666 667 if (key == null) { 668 throw new CmsIllegalArgumentException( 669 Messages.get().container(Messages.ERR_USER_ADDINFO_KEY_NULL_1, getFullName())); 670 } 671 m_additionalInfo.put(key, value); 672 } 673 674 /** 675 * Sets the address line of this user.<p> 676 * 677 * @param address the address line to set 678 */ 679 public void setAddress(String address) { 680 681 setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_ADDRESS, address); 682 } 683 684 /** 685 * Sets the city information of this user.<p> 686 * 687 * @param city the city information to set 688 */ 689 public void setCity(String city) { 690 691 setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_CITY, city); 692 } 693 694 /** 695 * Sets the country information of this user.<p> 696 * 697 * @param country the city information to set 698 */ 699 public void setCountry(String country) { 700 701 setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_COUNTRY, country); 702 } 703 704 /** 705 * @see org.opencms.security.CmsPrincipal#setDescription(java.lang.String) 706 */ 707 @Override 708 public void setDescription(String description) { 709 710 setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION, description); 711 } 712 713 /** 714 * Sets the email address of this user.<p> 715 * 716 * @param email the email address to set 717 */ 718 public void setEmail(String email) { 719 720 checkEmail(email); 721 if (email != null) { 722 email = email.trim(); 723 } 724 m_email = email; 725 } 726 727 /** 728 * Sets the first name of this user.<p> 729 * 730 * @param firstname the name to set 731 */ 732 public void setFirstname(String firstname) { 733 734 OpenCms.getValidationHandler().checkFirstname(firstname); 735 if (firstname != null) { 736 firstname = firstname.trim(); 737 } 738 m_firstname = firstname; 739 } 740 741 /** 742 * Sets the institution information of this user.<p> 743 * 744 * @param institution the institution information to set 745 */ 746 public void setInstitution(String institution) { 747 748 setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_INSTITUTION, institution); 749 } 750 751 /** 752 * Sets the last login time stamp of this user.<p> 753 * 754 * @param value the last login time stamp to set 755 */ 756 public void setLastlogin(long value) { 757 758 m_isTouched = true; 759 m_lastlogin = value; 760 } 761 762 /** 763 * Sets the last name of this user.<p> 764 * 765 * @param lastname the name to set 766 */ 767 public void setLastname(String lastname) { 768 769 OpenCms.getValidationHandler().checkLastname(lastname); 770 if (lastname != null) { 771 lastname = lastname.trim(); 772 } 773 m_lastname = lastname; 774 } 775 776 /** 777 * Sets the managed flag for this user to the given value.<p> 778 * 779 * @param value the value to set 780 */ 781 public void setManaged(boolean value) { 782 783 if (isManaged() != value) { 784 setFlags(getFlags() ^ I_CmsPrincipal.FLAG_USER_MANAGED); 785 } 786 } 787 788 /** 789 * Sets the password of this user.<p> 790 * 791 * @param value the password to set 792 */ 793 public void setPassword(String value) { 794 795 try { 796 OpenCms.getPasswordHandler().validatePassword(value); 797 } catch (CmsSecurityException e) { 798 throw new CmsIllegalArgumentException(e.getMessageContainer()); 799 } 800 m_password = value; 801 } 802 803 /** 804 * Sets the zip code information of this user.<p> 805 * 806 * @param zipcode the zip code information to set 807 */ 808 public void setZipcode(String zipcode) { 809 810 checkZipCode(zipcode); 811 if (zipcode != null) { 812 zipcode = zipcode.toUpperCase(); 813 } 814 setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_ZIPCODE, zipcode); 815 } 816 817 /** 818 * @see java.lang.Object#toString() 819 */ 820 @Override 821 public String toString() { 822 823 StringBuffer result = new StringBuffer(); 824 result.append("[User]"); 825 result.append(" name:"); 826 result.append(getName()); 827 result.append(" id:"); 828 result.append(m_id); 829 result.append(" flags:"); 830 result.append(getFlags()); 831 result.append(" description:"); 832 result.append(getDescription()); 833 return result.toString(); 834 } 835 836 /** 837 * Sets the "touched" status of this user to <code>true</code>.<p> 838 */ 839 public void touch() { 840 841 m_isTouched = true; 842 } 843}