001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH (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, 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;
045
046/**
047 * A user principal in the OpenCms permission system.<p>
048 *
049 * A user in OpenCms is uniquely defined by its user named returned by
050 * <code>{@link #getName()}</code>.<p>
051 * 
052 * Basic users in OpenCms are users that can access the OpenCms Workplace.
053 * Moreover, the user must be created by another user with the
054 * <code>{@link org.opencms.security.CmsRole#ACCOUNT_MANAGER}</code> role.
055 * These users are "content managers" that actually have write permissions in 
056 * at last some parts of the VFS.<p>
057 * 
058 * Another possibility is to have users in a 'Guests' group.
059 * These users do not have access to the OpenCms Workplace. 
060 * However, an user in a 'Guests' group can be created by every user, for example 
061 * the "Guest" user. The main use case is that these users are used for users of 
062 * the website that can generate their own accounts, in a "please register your 
063 * account..." scenario. 
064 * These user accounts can then be used to build personalized web sites.<p>
065 * 
066 * @since 6.0.0
067 * 
068 * @see CmsGroup 
069 */
070public class CmsUser extends CmsPrincipal implements Cloneable {
071
072    /** Storage for additional user information. */
073    private Map<String, Object> m_additionalInfo;
074
075    /** The creation date. */
076    private long m_dateCreated;
077
078    /**  The email of the user. */
079    private String m_email;
080
081    /** The first name of this user. */
082    private String m_firstname;
083
084    /** Boolean flag whether the last-login time stamp of this user was modified. */
085    private boolean m_isTouched;
086
087    /** The last login date of this user. */
088    private long m_lastlogin;
089
090    /** The last name of this user. */
091    private String m_lastname;
092
093    /** The password of this user. */
094    private String m_password;
095
096    /**
097     * Creates a new, empty OpenCms user principal.<p>
098     *
099     * Mostly intended to be used with the <code>org.opencms.workplace.tools.accounts.A_CmsEditUserDialog</code>.<p>
100     */
101    public CmsUser() {
102
103        this(
104            null,
105            "",
106            "",
107            "",
108            "",
109            "",
110            0,
111            I_CmsPrincipal.FLAG_ENABLED,
112            System.currentTimeMillis(),
113            Collections.singletonMap(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION, (Object)""));
114    }
115
116    /**
117     * Creates a new OpenCms user principal.<p>
118     * 
119     * @param id the unique id of the new user
120     * @param name the fully qualified name of the new user
121     * @param password the password of the user
122     * @param firstname the first name
123     * @param lastname the last name
124     * @param email the email address
125     * @param lastlogin time stamp 
126     * @param flags flags
127     * @param dateCreated the creation date
128     * @param additionalInfo user related information
129     */
130    public CmsUser(
131        CmsUUID id,
132        String name,
133        String password,
134        String firstname,
135        String lastname,
136        String email,
137        long lastlogin,
138        int flags,
139        long dateCreated,
140        Map<String, Object> additionalInfo) {
141
142        m_id = id;
143        m_name = name;
144        m_password = password;
145        m_firstname = firstname;
146        m_lastname = lastname;
147        m_email = email;
148        m_lastlogin = lastlogin;
149        m_flags = flags;
150        m_dateCreated = dateCreated;
151        if (additionalInfo != null) {
152            m_additionalInfo = new HashMap<String, Object>(additionalInfo);
153        } else {
154            m_additionalInfo = new HashMap<String, Object>();
155        }
156        if (m_additionalInfo.get(CmsUserSettings.ADDITIONAL_INFO_ADDRESS) == null) {
157            m_additionalInfo.put(CmsUserSettings.ADDITIONAL_INFO_ADDRESS, "");
158        }
159        if (m_additionalInfo.get(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION) == null) {
160            m_additionalInfo.put(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION, "");
161        }
162    }
163
164    /**
165     * Validates an email address.<p>
166     * 
167     * That means, the parameter should only be composed by digits and standard english letters, points, underscores and exact one "At" symbol.<p>
168     * 
169     * @param email the email to validate
170     */
171    public static void checkEmail(String email) {
172
173        OpenCms.getValidationHandler().checkEmail(email);
174    }
175
176    /**
177     * Validates a zip code.<p>
178     * 
179     * That means, the parameter should only be composed by digits and standard english letters.<p>
180     * 
181     * @param zipcode the zip code to validate
182     */
183    public static void checkZipCode(String zipcode) {
184
185        OpenCms.getValidationHandler().checkZipCode(zipcode);
186    }
187
188    /**
189     * Returns the "full" name of the given user in the format <code>"{firstname} {lastname} ({username})"</code>,
190     * or the empty String <code>""</code> if the user is null.<p>
191     * 
192     * @param user the user to get the full name from
193     * @return the "full" name the user
194     * 
195     * @see #getFullName() 
196     */
197    public static String getFullName(CmsUser user) {
198
199        if (user == null) {
200            return "";
201        } else {
202            return user.getFullName();
203        }
204    }
205
206    /**
207     * Returns the institution information of this user.<p>
208     * 
209     * This information is stored in the "additional information" storage map
210     * using the key <code>{@link CmsUserSettings#ADDITIONAL_INFO_INSTITUTION}</code>.<p>
211     * 
212     * @return the institution information of this user
213     */
214    public String getInstitution() {
215
216        return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_INSTITUTION);
217    }
218
219    /**
220     * Checks if the provided user name is a valid user name and can be used as an argument value 
221     * for {@link #setName(String)}.<p> 
222     * 
223     * @param name the user name to check
224     * 
225     * @throws CmsIllegalArgumentException if the check fails
226     */
227    public void checkName(String name) throws CmsIllegalArgumentException {
228
229        OpenCms.getValidationHandler().checkUserName(name);
230    }
231
232    /**
233     * @see java.lang.Object#clone()
234     */
235    @Override
236    public Object clone() {
237
238        return new CmsUser(
239            m_id,
240            m_name,
241            m_password,
242            m_firstname,
243            m_lastname,
244            m_email,
245            m_lastlogin,
246            m_flags,
247            m_dateCreated,
248            m_additionalInfo);
249    }
250
251    /**
252     * Deletes a value from this users "additional information" storage map.<p>
253     *
254     * @param key the additional user information to delete
255     * 
256     * @see #getAdditionalInfo()
257     */
258    public void deleteAdditionalInfo(String key) {
259
260        m_additionalInfo.remove(key);
261    }
262
263    /**
264     * Returns this users complete "additional information" storage map.<p>
265     *
266     * The "additional information" storage map is a simple {@link java.util.Map}
267     * that can be used to store any key / value pairs for the user.
268     * Some information parts of the users address are stored in this map
269     * by default.<p>
270     * 
271     * @return this users complete "additional information" storage map
272     */
273    public Map<String, Object> getAdditionalInfo() {
274
275        return m_additionalInfo;
276    }
277
278    /**
279     * Returns a value from this users "additional information" storage map,
280     * or <code>null</code> if no value for the given key is available.<p>
281     * 
282     * @param key selects the value to return from the "additional information" storage map
283     * 
284     * @return the selected value from this users "additional information" storage map
285     * 
286     * @see #getAdditionalInfo()
287     */
288    public Object getAdditionalInfo(String key) {
289
290        return m_additionalInfo.get(key);
291    }
292
293    /**
294     * Returns the address line of this user.<p>
295     *
296     * @return the address line of this user
297     */
298    public String getAddress() {
299
300        return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_ADDRESS);
301    }
302
303    /**
304     * Returns the city information of this user.<p>
305     * 
306     * This information is stored in the "additional information" storage map
307     * using the key <code>{@link CmsUserSettings#ADDITIONAL_INFO_CITY}</code>.<p>
308     * 
309     * @return the city information of this user
310     */
311    public String getCity() {
312
313        return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_CITY);
314    }
315
316    /**
317     * Returns the country information of this user.<p>
318     *
319     * This information is stored in the "additional information" storage map
320     * using the key <code>{@link CmsUserSettings#ADDITIONAL_INFO_COUNTRY}</code>.<p>
321     *
322     * @return the country information of this user
323     */
324    public String getCountry() {
325
326        return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_COUNTRY);
327    }
328
329    /**
330     * Returns the creation date.<p>
331     *
332     * @return the creation date
333     */
334    public long getDateCreated() {
335
336        return m_dateCreated;
337    }
338
339    /**
340     * @see org.opencms.security.CmsPrincipal#getDescription()
341     */
342    @Override
343    public String getDescription() {
344
345        return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION);
346    }
347
348    /**
349     * Returns the description of this organizational unit.<p>
350     *
351     * @param locale the locale
352     *
353     * @return the description of this organizational unit
354     */
355    public String getDescription(Locale locale) {
356
357        CmsMacroResolver macroResolver = new CmsMacroResolver();
358        macroResolver.setMessages(org.opencms.db.generic.Messages.get().getBundle(locale));
359        return macroResolver.resolveMacros((String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION));
360    }
361
362    /**
363     * @see org.opencms.security.CmsPrincipal#getDisplayName(org.opencms.file.CmsObject, java.util.Locale)
364     */
365    @Override
366    public String getDisplayName(CmsObject cms, Locale locale) throws CmsException {
367
368        if (OpenCms.getOrgUnitManager().getOrganizationalUnits(cms, "", true).size() > 0) {
369            return org.opencms.security.Messages.get().getBundle(locale).key(
370                org.opencms.security.Messages.GUI_PRINCIPAL_DISPLAY_NAME_2,
371                getFullName(),
372                OpenCms.getOrgUnitManager().readOrganizationalUnit(cms, getOuFqn()).getDisplayName(locale));
373        } else {
374            return getFullName();
375        }
376    }
377
378    /**
379     * Returns the email address of this user.<p>
380     *
381     * @return the email address of this user
382     */
383    public String getEmail() {
384
385        return m_email;
386    }
387
388    /**
389     * Returns the first name of this user.<p>
390     *
391     * @return the first name of this user
392     */
393    public String getFirstname() {
394
395        return m_firstname;
396    }
397
398    /**
399     * Returns the "full" name of the this user in the format <code>"{firstname} {lastname} ({username})"</code>.<p>
400     * 
401     * @return the "full" name this user
402     */
403    public String getFullName() {
404
405        StringBuffer buf = new StringBuffer();
406        String first = getFirstname();
407        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(first)) {
408            buf.append(first);
409            buf.append(" ");
410        }
411        String last = getLastname();
412        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(last)) {
413            buf.append(last);
414            buf.append(" ");
415        }
416        buf.append("(");
417        buf.append(getSimpleName());
418        buf.append(")");
419        return buf.toString();
420    }
421
422    /**
423     * Returns the time of the last login of this user.<p>
424     *
425     * @return the time of the last login of this user
426     */
427    public long getLastlogin() {
428
429        return m_lastlogin;
430    }
431
432    /**
433     * Returns the last name of this user.<p>
434     *
435     * @return the last name of this user
436     */
437    public String getLastname() {
438
439        return m_lastname;
440    }
441
442    /**
443     * Returns the encrypted user password.<p>
444     *
445     * @return the encrypted user password
446     */
447    public String getPassword() {
448
449        return m_password;
450    }
451
452    /**
453     * Returns the zip code information of this user.<p>
454     * 
455     * This information is stored in the "additional information" storage map
456     * using the key <code>{@link CmsUserSettings#ADDITIONAL_INFO_ZIPCODE}</code>.<p>
457     *
458     * @return the zip code information of this user 
459     */
460    public String getZipcode() {
461
462        return (String)getAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_ZIPCODE);
463    }
464
465    /**
466     * @see org.opencms.security.I_CmsPrincipal#isGroup()
467     */
468    @Override
469    public boolean isGroup() {
470
471        return false;
472    }
473
474    /**
475     * Checks if this user is the default guest user.<p>
476     * 
477     * @return <code>true</code> if this user is the default guest user
478     */
479    public boolean isGuestUser() {
480
481        return OpenCms.getDefaultUsers().isUserGuest(getName());
482    }
483
484    /**
485     * Returns <code>true</code> if this user is not able to manage itself.<p> 
486     * 
487     * @return <code>true</code> if this user is not able to manage itself 
488     */
489    public boolean isManaged() {
490
491        return (getFlags() & I_CmsPrincipal.FLAG_USER_MANAGED) == I_CmsPrincipal.FLAG_USER_MANAGED;
492    }
493
494    /**
495     * Returns <code>true</code> if this user was touched.<p>
496     * 
497     * @return boolean true if this user was touched
498     */
499    public boolean isTouched() {
500
501        return m_isTouched;
502    }
503
504    /**
505     * @see org.opencms.security.I_CmsPrincipal#isUser()
506     */
507    @Override
508    public boolean isUser() {
509
510        return true;
511    }
512
513    /**
514     * Checks if the user is marked as webuser.<p>
515     * 
516     * @return <code>true</code> if the user is marked as webuser
517     */
518    public boolean isWebuser() {
519
520        return (getFlags() & FLAG_USER_WEBUSER) == FLAG_USER_WEBUSER;
521    }
522
523    /**
524     * Sets this users complete "additional information" storage map to the given value.<p>
525     * 
526     * @param additionalInfo the complete "additional information" map to set
527     * 
528     * @see #getAdditionalInfo()
529     */
530    public void setAdditionalInfo(Map<String, Object> additionalInfo) {
531
532        m_additionalInfo = additionalInfo;
533    }
534
535    /**
536     * Stores a value in this users "additional information" storage map with the given access key.<p>
537     * 
538     * @param key the key to store the value under
539     * @param value the value to store in the users "additional information" storage map
540     * 
541     * @see #getAdditionalInfo()
542     */
543    public void setAdditionalInfo(String key, Object value) {
544
545        if (key == null) {
546            throw new CmsIllegalArgumentException(Messages.get().container(
547                Messages.ERR_USER_ADDINFO_KEY_NULL_1,
548                getFullName()));
549        }
550        m_additionalInfo.put(key, value);
551    }
552
553    /**
554     * Sets the address line of this user.<p>
555     *
556     * @param address the address line to set
557     */
558    public void setAddress(String address) {
559
560        setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_ADDRESS, address);
561    }
562
563    /**
564     * Sets the city information of this user.<p>
565     * 
566     * @param city the city information to set
567     */
568    public void setCity(String city) {
569
570        setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_CITY, city);
571    }
572
573    /**
574     * Sets the country information of this user.<p>
575     * 
576     * @param country the city information to set
577     */
578    public void setCountry(String country) {
579
580        setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_COUNTRY, country);
581    }
582
583    /**
584     * @see org.opencms.security.CmsPrincipal#setDescription(java.lang.String)
585     */
586    @Override
587    public void setDescription(String description) {
588
589        setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION, description);
590    }
591
592    /**
593     * Sets the email address of this user.<p>
594     *
595     * @param email the email address to set
596     */
597    public void setEmail(String email) {
598
599        checkEmail(email);
600        if (email != null) {
601            email = email.trim();
602        }
603        m_email = email;
604    }
605
606    /**
607     * Sets the first name of this user.<p>
608     *
609     * @param firstname the name to set
610     */
611    public void setFirstname(String firstname) {
612
613        OpenCms.getValidationHandler().checkFirstname(firstname);
614        if (firstname != null) {
615            firstname = firstname.trim();
616        }
617        m_firstname = firstname;
618    }
619
620    /**
621     * Sets the institution information of this user.<p>
622     * 
623     * @param institution the institution information to set
624     */
625    public void setInstitution(String institution) {
626
627        setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_INSTITUTION, institution);
628    }
629
630    /**
631     * Sets the last login time stamp of this user.<p>
632     *
633     * @param value the last login time stamp to set
634     */
635    public void setLastlogin(long value) {
636
637        m_isTouched = true;
638        m_lastlogin = value;
639    }
640
641    /**
642     * Sets the last name of this user.<p>
643     *
644     * @param lastname the name to set
645     */
646    public void setLastname(String lastname) {
647
648        OpenCms.getValidationHandler().checkLastname(lastname);
649        if (lastname != null) {
650            lastname = lastname.trim();
651        }
652        m_lastname = lastname;
653    }
654
655    /**
656     * Sets the managed flag for this user to the given value.<p>
657     * 
658     * @param value the value to set
659     */
660    public void setManaged(boolean value) {
661
662        if (isManaged() != value) {
663            setFlags(getFlags() ^ I_CmsPrincipal.FLAG_USER_MANAGED);
664        }
665    }
666
667    /**
668     * Sets the password of this user.<p>
669     *
670     * @param value the password to set
671     */
672    public void setPassword(String value) {
673
674        try {
675            OpenCms.getPasswordHandler().validatePassword(value);
676        } catch (CmsSecurityException e) {
677            throw new CmsIllegalArgumentException(e.getMessageContainer());
678        }
679        m_password = value;
680    }
681
682    /**
683     * Sets the zip code information of this user.<p>
684     * 
685     * @param zipcode the zip code information to set
686     */
687    public void setZipcode(String zipcode) {
688
689        checkZipCode(zipcode);
690        if (zipcode != null) {
691            zipcode = zipcode.toUpperCase();
692        }
693        setAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_ZIPCODE, zipcode);
694    }
695
696    /**
697     * @see java.lang.Object#toString()
698     */
699    @Override
700    public String toString() {
701
702        StringBuffer result = new StringBuffer();
703        result.append("[User]");
704        result.append(" name:");
705        result.append(getName());
706        result.append(" id:");
707        result.append(m_id);
708        result.append(" flags:");
709        result.append(getFlags());
710        result.append(" description:");
711        result.append(getDescription());
712        return result.toString();
713    }
714
715    /**
716     * Sets the "touched" status of this user to <code>true</code>.<p>
717     */
718    public void touch() {
719
720        m_isTouched = true;
721    }
722}