head	1.5;
access;
symbols;
locks; strict;
comment	@# @;


1.5
date	2001.01.26.05.24.05;	author edk;	state dead;
branches;
next	1.4;

1.4
date	2001.01.25.02.00.54;	author edk;	state Exp;
branches;
next	1.3;

1.3
date	2001.01.25.01.38.06;	author leonardr;	state Exp;
branches;
next	1.2;

1.2
date	2001.01.24.22.24.36;	author leonardr;	state Exp;
branches;
next	1.1;

1.1
date	2001.01.24.21.41.48;	author leonardr;	state Exp;
branches;
next	;


desc
@@


1.5
log
@revert this stuff to its state as of 2001/01/24 12:42:00 GMT -- with
the following exceptions, which have some different modifications so
they'll work with changes which have happened in joist:

ProjectNewsEdit.java
SkinManager.java
SkinStyleElementValueManager.java
StyleElementManager.java
StyleManager.java

it compiles.  i dunno if it works, though.
@
text
@/* ================================================================
 * Copyright (c) 2000 CollabNet.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if
 * any, must include the following acknowlegement: "This product includes
 * software developed by CollabNet (http://www.collab.net/)."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of CollabNet.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals on behalf of CollabNet.
 */

package org.tigris.helm.database;

import java.util.*;
import java.sql.*;

import org.webmacro.util.*;
import org.webmacro.servlet.*;

import org.apache.turbine.services.db.TurbineDB;
import org.apache.turbine.util.db.pool.DBConnection;

import com.workingdogs.village.*;

import org.joist.database.Criterion;
import org.joist.database.DataManager;
import org.joist.database.TableManager;
import org.joist.database.UserType;
import org.joist.util.*;

import org.tigris.helm.DoesNotExist;
import org.tigris.helm.AlreadyExists;

/**
  * Manages users, including adding, retrieving, updating, and deleting.
  *
  * @@author David C. Pellegrini <A HREF="mailto:davidp@@dataweb-systems.com">davidp@@dataweb-systems.com</A>
  * @@author Leonard Richardson <A HREF="mailto:leonardr@@collab.net">leonardr@@collab.net</A>
  * @@author <A HREF="mailto:dlr@@collab.net">Daniel Rall</A>
  * @@version $Revision: 1.4 $
  *
  * Copyright (c) 1999 dataweb systems, inc.
  * Copyright (c) 1999-2001 CollabNet, Inc.
  */

public class UserManager extends TableManager
{
    protected static Log log = new Log("userMgr", "User manager");
    protected static boolean debug = true;

    public static final String TABLE_NAME = "User";
    public static final String DOMAIN_ID = "domainID";
    public static final String USER_ID = "userID";
    public static final String LOGIN_ID = "loginID";
    public static final String EMAIL = "email";
    public static final String NAME = "name";
    public static final String PASSWORD = "password";
    public static final String TYPE = "type";
    public static final String ORGANIZATION = "organization";

    /**
     * Create an instance with a data manager.
     *
     * @@param dataMgr The associated data manager.
     */
    public UserManager(DataManager dataMgr)
    {
	super(dataMgr, new KeyDef().addAttrib(USER_ID));
    }

    /**
     * Returns a SQL clause fragment for sorting a user list alphabetically.
     *
     * @@return The <code>order by</code> clause.
     *
     */
    public String alphabeticalOrderBy()
    {
        return " ORDER BY " + NAME;
    }

    public Criterion domainMatchCriterion(String domainID)
        throws DBException
    {
        DomainManager domMgr = (DomainManager)getDataManager().getManager
                ("org.tigris.helm.database.DomainManager");            

        String hostDomainID = null;
        try {
            hostDomainID = domMgr.getHostDomain().getValue(DomainManager.DOMAIN_ID).asString();
        } catch (Exception e) {
            throw new DBException(e);
        }
        Criterion c = new Criterion(DOMAIN_ID, hostDomainID);
        if (domainID != null)  
        {
            c.or(new Criterion(DOMAIN_ID, domainID));
        }
        return c;
    }

    ////////////////////////////////////////////////////////////////
    // Accessor methods.
    ////////////////////////////////////////////////////////////////

    /**
     * Gets the database key associated with the special user that represents 
     * the "all users in domain" user group for the specified domani. 
     *
     * @@param domainID      The database key of the domain to retrieve the 
     *                      special user for.
     */
    public String getUserIDForDomainUserGroup (String domainID)
        throws DBException
    {
        String userID = null;
        Criterion c = new Criterion(DOMAIN_ID, domainID);
        c.and(new Criterion(USER_TYPE, UserType.DOMAIN));
        Record r = firstMatchingUser(c);
        if (r != null)
        {
            try {
                userID = r.getValue(USER_ID).asString();
            } catch (DataSetException e) {
                throw new DBException(e);
            }
        } else {
            throw new DBException("No domain user for domain " + domainID + "!");
        }
        return userID;
    }

    /**
     * Gets the database key associated with the special user that represents 
     * the group of all host users.
     *
     */
    public String getUserIDForHostGroup ()
        throws DBException
    {
        String userID = null;
        Criterion c = (new Criterion(USER_TYPE, UserType.HOST));
        Record r = firstMatchingUser(c);
        if (r != null)
        {
            try {
                userID = r.getValue(USER_ID).asString();
            } catch (DataSetException e) {
                throw new DBException(e);
            }
        } else {
            throw new DBException("No host user!");
        }
        return userID;
    }

    /**
     * Throws an exception if the specified information corresponds to an
     * existing user.
     *  
     * @@param domainID    ID of the domain to check
     * @@param loginID     Login ID of the user to search for.
     * @@param
     */
    public void assertUserNonexistance(String domainID, String loginID)
        throws DBException, AlreadyExists
    {
        /* TODO: Check the host domain as well. */
        Criterion c = new Criterion(LOGIN_ID, loginID);
        c.and(new Criterion(DOMAIN_ID, domainID));
        Record user = getFirstMatchingUser(c);
        if (user != null)
        {
            throw new AlreadyExists
                ("User in domain " + domainID + " with loginID " + loginID);
        }
    }

    /**
     * Gets the userID for user "**Nobody"
     */
    public String getNobodyUserID()
        throws DBException
    {
	String nobodyUserID = null;
        try {
            Record r = getUserForLoginID(null, "**Nobody");
            nobodyUserID = r.getValue(UserManager.USER_ID).toString();
        } catch (Exception e) {
            throw new DBException(e);
        }
	return nobodyUserID;
    }

    /**
     * Gets a Record for a particular user by userID.
     *
     * @@param userID The database key of the user to get.
     * @@return       Record for the requested user.
     *
     * @@exception DBException if a database error occurs.
     * @@exception DoesNotExist if there is no user with the given ID.
     */
    public Record getUser (String userID)
        throws DBException, DoesNotExist
    {
        Criterion c = new Criterion(USER_ID, userID);
        Record user = getFirstMatchingUser(c);   
        if (user == null)
        {
            throw new DoesNotExist("User with ID " + userID);
        }
        return user;
    }

    /**
     * Gets a Record for a particular user by user name. Note that
     * this is not guaranteed to return a unique result since the
     * name field in the database is not unique.
     *
     * @@param name The name of the user to get.
     * @@return     Record for the requested user.
     *
     * @@exception DBException if a database error occurs.
     * @@exception DoesNotExist if there is no user with the given name.
     */   
    public Record getUserForName (String domainID, String name)
        throws DBException, DoesNotExist
    {
        Criterion c = new Criterion(NAME, name);
        c.and(domainMatchCriterion(domainID));
        Record user = getFirstMatchingUser(c);
        if (user == null)
        {
            throw new DoesNotExist("User with name " + name + " in domain " + domainID);
        }
        return user;
    }

    /**
     * Gets a Record for a particular user by domain and login ID.
     *
     * @@param name The login ID of the user to get.
     * @@param domain The domain in which we're looking for this user.
     * @@return     Record for the requested user.
     *
     * @@exception DBException if a database error occurs.
     * @@exception DoesNotExist if there is no user with the given login ID.
     */   
    public Record getUserForLoginID (String domainID, String loginID)
        throws DBException, DoesNotExist
    {        
        Criterion c = new Criterion(LOGIN_ID, loginID);
        c.and(domainMatchCriterion(domainID));
        Record user = getFirstMatchingUser(c);   
        if (user == null)
        {
            throw new DoesNotExist("User with login ID " + loginID + " in domain " + domainID);
        }
        return user;
    }

    /**
     * Gets a Record for a particular user by email address. Note that
     * this is not guaranteed to return a unique result since the
     * email address field in the database is not unique.
     *
     * @@param address The email address of the user to get.
     * @@return     Record for the requested user.
     *
     * @@exception DBException if a database error occurs.
     * @@exception DoesNotExist if there is no user with the given email address.
     */   
    public Record getUserForEmail (String address)
        throws DBException, DoesNotExist
    {
        Criterion c = new Criterion(EMAIL, address);
        Record user = getFirstMatchingUser(c);
        if (user == null)
        {
            throw new DoesNotExist("User with email address " + address);
        }
        return user;
    }

    /**
     * Retrives a list of all users.
     *
     * @@see #getUserList()
     */
    public DataSet getUserList()
        throws DBException
    {
        return getUserList(null);
    }

    /**
     * Retreives a list of users of the specified type.
     *
     * @@param type The type of users to retreive, or <code>null</code> if all 
     *             types are okay.
     * @@return     A list of all the users.
     *
     * @@exception DBException
     */
    public DataSet getUserList(String type)
	throws DBException
    {
        Criterion c = null;
        if (type != null)
        {
            c = new Criterion(TYPE, type);
        }
        DataSet users = getUsers(c);
        return users;
    }

    /**
     * Returns the first user matching a given Criterion. 
     *
     * @@param criterion Criterion to use in select.
     *
     * @@exception DBException if a database error occurs.
     *
     * @@return Null if no matching user, first user in recordset otherwise.
     */
    private Record getFirstMatchingUser(Criterion criterion)
        throws DBException
    {
        Record r = null;
        try {
            DataSet s = getUsers(criterion);
            if (s != null && s.containsRecord(0))
            {
                r = s.getRecord(0);
            }
        } catch (DataSetException e) {
            throw new DBException(e);
        }

        return r;
    }

    /**
     * Returns users matching a given criterion, sorted by real name.
     *
     * @@param criterion Criterion to use in select.
     *
     * @@exception DBException if a database error occurs.
     */
    public DataSet getUsers(Criterion criterion)
    throws DBException
    {
        DataSet s = null;
        try {
            s = runSelect(TABLE_NAME, criterion, TABLE_NAME + "." + NAME);
        } catch (Exception e) {
            throw new DBException(e);
        }
        return s;
    }

    ////////////////////////////////////////////////////////////////
    // Mutator methods.
    ////////////////////////////////////////////////////////////////

    /**
     * Updates an existing user or adds a new user to the database 
     * (depending on whether given a <code>userID</code> or not).
     *
     * Note: This method only changes the database. It does not run
     * scripts.
     *
     * @@param domainID      Domain in which the new user resides.
     * @@param loginID       Login ID of the new user.
     * @@param email         Email Address of the new user.
     * @@param realName      Real name of the new user.
     * @@param organization  Organization with which the new user is associated.
     * @@param password      Unencrypted password for the new user.
     * @@param type          Type of the user.
     * @@return  The record for the updated user.
     *
     * @@exception DBException
     */
    public synchronized Record addUser 
        (String domainID, String loginID, String email, 
         String realName, String organization, 
         String password, String type)
        throws DBException, AlreadyExists
    {
        assertUserNonexistance(domainID, loginID);
        Record user = null;
        try {
            user = updateUser(null, domainID, loginID, email, realName, 
                              organization, password, type);
        } catch (DoesNotExist ignore) {
            //Can't happen on new user creation
        }
        return user;
    }

    /**
     * Updates an existing user or adds a new user to the database 
     * (depending on whether given a <code>userID</code> or not).
     *
     * Note: This method only changes the database. It does not run
     * scripts.
     *
     * @@param userID        ID of the user to edit (leave null to add new)
     * @@param domainID      Domain in which the user resides.
     * @@param loginID       Login ID of the user.
     * @@param email         Email Address of the user.
     * @@param realName      Real name of the user.
     * @@param organization  Organization with which the user is associated.
     * @@param password      Unencrypted password for the user.
     * @@param type          Type of the user.
     *
     * @@return  The record for the updated user.
     *
     * @@exception DBException
     */
    private Record updateUser (String userID, String domainID,
                               String loginID, String email, 
                               String realName, String organization, 
                               String password, String type)
        throws DBException, DoesNotExist
    {
        DBConnection dbConn = null;
        Record user = null;
        TableDataSet users = null;

        try
        {
            dbConn = TurbineDB.getConnection();
            Connection connection = dbConn.getConnection();           

            String oldPassword = null;
            String encryptedPassword = null;

            if (userID != null)
            {
                user = getUser(userID);
                oldPassword = user.getValue(PASSWORD).asString();
            } else {
                users = new TableDataSet (connection, TABLE_NAME, keydef);
                user = users.addRecord();                
            }
            
            if (password != null)
            {
                encryptedPassword = encryptPassword(connection, password);
            }

            // Do update.
            if (domainID != null) user.setValue(DOMAIN_ID, domainID);
            if (loginID != null) user.setValue(LOGIN_ID, loginID);
            if (email != null) user.setValue(EMAIL, email);
            if (realName != null) user.setValue(NAME, realName);
            if (organization != null) user.setValue(ORGANIZATION, organization);
            if (encryptedPassword != null) user.setValue(PASSWORD, encryptedPassword);
            user.save();

            if (userID == null)
            {
                // NOTE: There is no way to refresh a Village Record which has
                // been created using TableDataSet.addRecord().
                userID = getLastInsertedID(connection).toString();
                user.setValue(USER_ID, userID);
            }
        } catch (Exception e) {
            throw new DBException(e);
        } finally {
            registerToClose(users);
            try {
                TurbineDB.releaseConnection(dbConn);
            } catch (Exception e) {
                throw new DBException(e);
            }
        }
        
        return user;
    }

    /**
     *  Deletes an existing user record from the database
     *
     * @@param	userID    the ID of the user to delete
     * @@exception	DBException if a database error occurs.
     */
    public void deleteUser (String userID)
	throws DBException
    {
        Record user = null;
        try {
            user = getUser(userID);
        } catch (DoesNotExist ignore) {}

        if (user != null)
        {
            try {
                user.markToBeDeleted();
                user.save();
            } catch (DataSetException e) {
                throw new DBException(e);
            } catch (SQLException e) {
                throw new DBException(e);
            }
        }
    }

    /**
     * Uses the database to encrypt the provided clear text password.
     *
     * @@param conn   The JDBC connection to use.
     * @@param passwd The clear text password to encrypt.
     * @@return       The encrypted password.
     */
    protected String encryptPassword (Connection conn, String passwd)
        throws SQLException
    {
        String encrypted = null;
        Statement stmt = conn.createStatement();
        try
        {
            StringBuffer buf = new StringBuffer("select PASSWORD(");
            buf.append(QuotedString.from(passwd)).append(')');
            ResultSet rset = stmt.executeQuery(buf.toString());

            if (rset.next())
            {
                encrypted = rset.getString(1);
            }
        }
        finally
        {
            if (stmt != null) stmt.close();
        }
        return encrypted;
    }
    
}
@


1.4
log
@registerToClose before calling TurbineDB.releaseConnection(dbConn)
@
text
@d75 1
a75 1
  * @@version $Revision: 1.3 $
@


1.3
log
@More TableManagers de-connectionified.
@
text
@d75 1
a75 1
  * @@version $Revision: 1.2 $
d508 1
a513 1
            registerToClose(users);
@


1.2
log
@Moved TableManagers to new keydef constructor and keydef-less runSelect.
@
text
@d75 1
a75 1
  * @@version $Revision: 1.1 $
d365 1
a365 1
        Record user = null;
d367 2
a368 2
            DataSet users = getUsers(criterion);
            if (users != null && users.containsRecord(0))
d370 1
a370 1
                user = users.getRecord(0);
d376 1
a376 1
        return user;
d420 4
a423 3
    public Record addUser (String domainID, String loginID, String email, 
                           String realName, String organization, 
                           String password, String type)
d483 2
a484 2

            if (!password.equals(oldPassword))
a486 3
            } else {
                // The encrypted value is checked for null before saving.
                encryptedPassword = oldPassword;
@


1.1
log
@Ported UserManager and RoleManager to Helm. Started moving other TableManagers toward a grab-connection-on-demand model. Massive breakage ensues. dlr and I are working on it.
@
text
@d75 1
a75 1
  * @@version $Revision: 1.56 $
d103 1
a103 9
	super(dataMgr);
    }

    /**
     * Returns a KeyDef object appropriate for this table.
     */
    public KeyDef keydef()
    {
        return new KeyDef().addAttrib(USER_ID);
d391 1
a391 1
            s = runSelect(TABLE_NAME, keydef(), criterion, TABLE_NAME + "." + NAME);
d479 1
a479 1
                users = new TableDataSet (connection, TABLE_NAME, keydef());
@

