<!---
	Name         : cfcs/user.cfc
	Author       : Raymond Camden 
	Created      : August 3, 2007
	Last Updated : 
	History      : 
	Purpose		 : 
--->

<cfcomponent displayName="User" hint="Basic User CFC" output="false">


	<cffunction name="init" access="public" returnType="user" output="false"
				hint="Returns an instance of the CFC initialized with the correct DSN.">
		<cfargument name="dsn" type="string" required="true" hint="DSN used for all operations in the CFC.">
		<cfargument name="dbtype" type="string" required="true" hint="Database type.">
		<cfargument name="tableprefix" type="string" required="true" hint="Table prefix.">
		
		<cfset variables.dsn = arguments.dsn>
		<cfset variables.dbtype = arguments.dbtype>
		<cfset variables.tableprefix = arguments.tableprefix>
		<cfset variables.lockname = "soundings_20_userlock">		
		<cfreturn this>
		
	</cffunction>

	<cffunction name="addUser" access="public" returnType="void" output="false">
		<cfargument name="username" type="string" required="true">
		<cfargument name="password" type="string" required="false" default="">
		<cfset var check = "">
		
		<cflock name="#variables.lockname#" type="exclusive" timeout="30">
			<!--- did we pick someone existing? --->

			<cfquery name="check" datasource="#variables.dsn#">
			select	username
			from	#variables.tableprefix#users
			where	username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.username#" maxlength="255">
			</cfquery>

			<cfif check.recordCount>
				<cfthrow message="A user by this name, #arguments.username#, already exists.">
			</cfif>

			
			<cfquery datasource="#variables.dsn#">
			insert into #variables.tableprefix#users(username,password)
			values(<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.username#" maxlength="255">,
			<cfqueryparam cfsqltype="cf_sql_varchar" value="#hash(arguments.password)#" maxlength="255">)
			</cfquery>
			
		</cflock>		
	</cffunction>

	<cffunction name="authenticate" access="public" returnType="boolean" output="false">
		<cfargument name="username" type="string" required="true">
		<cfargument name="password" type="string" required="true">
		<cfset var q = "">
		
		<cfquery name="q" datasource="#variables.dsn#">
		select	username
		from	#variables.tableprefix#users
		where	username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.username#" maxlength="255">
		and		password = <cfqueryparam cfsqltype="cf_sql_varchar" value="#hash(arguments.password)#" maxlength="255">
		</cfquery>
		
		<cfreturn q.recordCount is 1>
	</cffunction>

	<cffunction name="deleteUser" access="public" returnType="void" output="false">
		<cfargument name="username" type="string" required="true">

		<cfquery datasource="#variables.dsn#">
		delete	from #variables.tableprefix#users
		where	username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.username#" maxlength="255">
		</cfquery>
		
	</cffunction>
	
	<cffunction name="getUser" access="public" returnType="struct" output="false">
		<cfargument name="username" type="string" required="true">
		<cfset var q = "">
		<cfset var s = structNew()>
				
		<cfquery name="q" datasource="#variables.dsn#">
		select	username, password
		from	#variables.tableprefix#users
		where	username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.username#" maxlength="255">
		</cfquery>

		<cfset s.username = q.username>
		<cfset s.password = q.password>

		<cfreturn s>
	</cffunction>
		
	<cffunction name="getUsers" access="public" returnType="query" output="false">
		<cfset var q = "">
		
		<cfquery name="q" datasource="#variables.dsn#">
		select	username, password
		from	#variables.tableprefix#users
		order by username asc
		</cfquery>
		
		<cfreturn q>
	</cffunction>
	
	<cffunction name="updatePassword" access="public" returnType="void" output="false">
		<cfargument name="username" type="string" required="true">
		<cfargument name="oldpassword" type="string" required="true">
		<cfargument name="newpassword" type="string" required="true">

		<!--- ensure old password is right --->
		<cfif authenticate(arguments.username,arguments.oldpassword)>
			<cfquery datasource="#variables.dsn#">
			update	#variables.tableprefix#users
			set		password = <cfqueryparam cfsqltype="cf_sql_varchar" value="#hash(arguments.newpassword)#" maxlength="255">
			where	username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.username#" maxlength="255">
			</cfquery>
		<cfelse>
			<cfthrow message="Old password did not match.">
		</cfif>
	
	</cffunction>
	
	<cffunction name="updateUser" access="public" returnType="void" output="false">
		<cfargument name="originalusername" type="string" required="true">
		<cfargument name="username" type="string" required="true">
		<cfargument name="password" type="string" required="false" default="">
		<cfset var check = "">
		
		<!--- Logic is simple:
		If username changed, I need to check for uniqueness.
		If password has a value, I update and hash.
		So if username same as orig and no new password, might as well make like a banana and split.
		--->
		
		<cfif arguments.originalusername is arguments.username and arguments.password is "">
			<cfreturn>
		</cfif>

		<cflock name="#variables.lockname#" type="exclusive" timeout="30">
			<!--- did we change names? --->
			<cfif arguments.originalusername neq arguments.username>

				<cfquery name="check" datasource="#variables.dsn#">
				select	username
				from	#variables.tableprefix#users
				where	username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.username#" maxlength="255">
				</cfquery>

				<cfif check.recordCount>
					<cfthrow message="A user by this name, #arguments.username#, already exists.">
				</cfif>

			</cfif>
			
			<cfquery datasource="#variables.dsn#">
			update	#variables.tableprefix#users
			set		username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.username#" maxlength="255">
			<cfif len(arguments.password)>
			,password = <cfqueryparam cfsqltype="cf_sql_varchar" value="#hash(arguments.password)#" maxlength="255">
			</cfif>
			where 	username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.originalusername#" maxlength="255">
			</cfquery>
			
		</cflock>		
	</cffunction>

</cfcomponent>