Canvas 2 Beta Refresh

I've got a new version of the Canvas 2 Beta ready for testing. This update finally fixes the loginpath bug (thanks to a forum user for making it easy to reproduce) and adds security to file uploads.

This is it. I'm only going to add one more thing before releasing this application and it is a big one. Like BlogCFC, Canvas is going to support multiple Wikis in one database. This will make it easier to use for folks who may have a limited amount of databases at an ISP.

To make things interesting - you will be able to set the name of the Wiki ("name" being a string label to use in the database) in the XML, or do it at runtime. Why is that important? Being able to set the value at runtime means I can run multiple, virtual Wikis on the fly. Hmm, what site could I add that too?

Lastly - a question. Canvas 2 changes the "language" used to markup pages. How critical is it that I ship a tool to update your old markup?

The bits are attached to this blog entry.

Comments

Hey Ray 'bizzybee' Camden,

Thanks for updating yet another cool app!
How big are the changes to the language, if i can take care of it with a basic replace, I don't think a tool for that is necessary.
# Posted By Mingo Hagen | 2/26/07 7:53 AM
It is a simple text replacement. I don't have it in front of me right now, but it would be like [x] to [y]. If I _don't_ build a tool I'll at least document it.
# Posted By Raymond Camden | 2/26/07 8:20 AM
I am trying canvas wiki using ModelGlue but I get an error that I cannot undestand:

Could not find the ColdFusion Component ModelGlue.Core.XMLModelGlueLoader.
Please check that the given name is correct and that the component exists.

The error occurred in C:\CFusionMX7\wwwroot\canvaswiki\ModelGlue\ModelGlue.cfm: line 12

10 :          <cfset ModelGlue.configPath = expandPath(".") & "/config/ModelGlue.xml">
11 :          <cfparam name="ModelGlue_CONFIG_PATH" type="string" default="#ModelGlue.configPath#" />
12 :        <cfset application[ModelGlue_APP_KEY]= createObject("component", "ModelGlue.Core.XMLModelGlueLoader").init().createModelGlue(ModelGlue_CONFIG_PATH) />
13 :       </cfif>
14 :    </cflock>


The point is that the component is perfectly present in his root.

May you help me??

Thanks

Andrea
# Posted By Andrea | 3/2/07 3:37 PM
Hmm. Maybe make a cfmapping for Model-Glue? You aren't supposed to need one, but it could help.
# Posted By Raymond Camden | 3/2/07 3:55 PM
I had to add a mapping to the website to make it work. This is mainly coz we have internal and external ips and multiple domains on the same ip using host headers in IIS. So even though it loaded internally I had to add the mappings to make it work externally.
I just finished getting everything up and running in the last week , including changing the login function in the userRecord.cfc to do authentication from the database instead of hardcoded values. I got the authenticateUser code from Kurt Wiersma's Appbooster app, modified it , added it to the cfc and then modified the login function code.

here is the code for anyone who is interested. Sorry about the long comment with all the code. I was wondering if I wanted to set the dbname as a variable how would i do that? I am not extremely familiar with MG, I use Mach II.

It requires two tables in the db

user :: columns - firstname, lastname, userid (identity), usename, password, roleid and optional (email)

roles :: columns - roleid(identity int), role(varchar10)
1 sysop
2 admin
3 user


<cffunction name="authenticateUser" access="public" returntype="query" output="false">
   <cfargument name="username" required="yes" type="string">
   <cfargument name="password" required="yes" type="string">
   <cfargument name="roleid" required="no" type="string" default="">
   <cfset var qUsers = 0>
   <cfquery name="qUsers" datasource="CanvasWiki">
      SELECT u.userid, u.username, u.password, u.firstname, u.lastname, r.role
      FROM    gp_users u
         left join gp_roles r on u.roleid = r.roleid
      WHERE (1 = 1)
      AND u.username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.username#">
      AND u.password = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.password#">
      <cfif arguments.roleid neq "">
         AND r.roleid = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.roleid#">
      </cfif>
   </cfquery>
   <cfreturn qUsers>
</cffunction>

<cffunction name="login" access="public" hint="I log this user into the site" output="false" returntype="boolean">
   <!--- make this do some type of real authentication if desired--->
   <!--- you can find the plain-text passwords that match these users in the load() function --->
   <cfset qUser = authenticateUser(getUserName(), getPassword())>
   <cfif qUser.recordcount gt 0>
      <cfset setFirstName(qUser.firstName)>
      <cfset setLastName(qUser.lastName)>
      <cfset setUniqueId(qUser.userid)>
      <cfswitch expression="#qUser.role#">
         <cfcase value="sysop">
            <cfset setRoles("sysop,admin,user")>
         </cfcase>
         <cfcase value="admin">
            <cfset setRoles("admin,user")>
         </cfcase>
         <cfcase value="user">
            <cfset setRoles("user")>
         </cfcase>
         <cfdefaultcase><cfthrow message="Invalid User #qUser.role#123" ></cfdefaultcase>
      </cfswitch>
      <cfset setIsLoggedIn(true)>
   </cfif>

   <!--- Rays Code overridding with database authentication
   <cfif
         (getUserName() eq "sysop") and (getPasswordHash() eq "D681B218E5F4D053D919DA015D41C85B209479FCFAD00D0E4D5EC87856C10409")
         OR
         (getUserName() eq "admin") and (getPasswordHash() eq "8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A918")
         OR
         (getUserName() eq "user") and (getPasswordHash() eq "04F8996DA763B7A969B1028EE3007569EAF3A635486DDAB211D512C85B9DF8FB")
         >
      <!--- load() to set all the values for the current user --->
      <cfset load()>
      <cfset setIsLoggedIn(true)>
   </cfif>
   --->
   <!---
   <cfoutput>
      getUserName()=#getUserName()#<br />
      getpasswordHash()=#getpasswordHash()#<br />
      getIsLoggedIn()=#getIsLoggedIn()#<br />
      #_toString()#
      <!--- <cfabort> --->
   </cfoutput>
   --->
   <cfreturn getIsLoggedIn() />
</cffunction>
# Posted By Prem Radhakrishnan | 3/5/07 11:33 AM
I forgot to ask a couple of questions

1. Is there documentation other than the install.pdf?
2. If not how do you add more categories?
# Posted By Prem Radhakrishnan | 3/5/07 11:38 AM
Prem, the docs haven't been completed yet, but as for categories, it is free form. If you mark a page as cat X, then you now have a cat X. (If I remember my own app right. ;)
# Posted By Raymond Camden | 3/5/07 2:24 PM
It is adding the page in a new category if I put in a new category but the category is not showing up in the Categories List.
Bug maybe or am i doing something wrong

I added a new page with the content

Testing new categories addition [[Categories:Test Category]]


If I search for the page it comes up as

-----------------------------------------------------
Testing Categories

Testing new categories addition Categories:Test Category
--------------------------------------------------------

but if i look in category list theres still only

--------------------------------------------------------
Special: Categories

* General
---------------------------------------------------------
# Posted By Prem Radhakrishnan | 3/5/07 3:55 PM
Does it work if you put it on a line by itself, at the beginning of a line?
# Posted By Raymond Camden | 3/5/07 4:01 PM
This doesnt work either

[[Categories:Test2 Categories]] Testing categories again

Is this what you meant
# Posted By Prem | 3/5/07 5:35 PM
No. Put the [[ stuff by ITSELF, on one line. No other text.
# Posted By Raymond Camden | 3/5/07 6:09 PM
I tried
1.Just putting categories

--------------
[[Categories:Test]]
---------------

2. in two lines with content

------------------
Test
[[Categories:Test]]
------------------

neither works

and its going into the orphaned pages
# Posted By Prem | 3/5/07 6:26 PM
Ok - I can confirm this is broken. I'm looking into it.
# Posted By Raymond Camden | 3/5/07 8:23 PM
Oh duh. It is category, not categories. :) I even READ my own doc and ignored it. Using category:x it worked just fine.
# Posted By Raymond Camden | 3/5/07 8:28 PM
I feel like homer simpson DOH!!!

Thanks Ray. I will share the site as soon as I get some stuff in there.
# Posted By Prem Radhakrishnan | 3/6/07 11:12 AM
Ray,
I had to fix some case inconsitancies in the factory.cfc to get it to work on my linux hosting @ HMS. Specifically you will have to exactly match the case of the references in the createObject calls to match the CFC filename case(or inject them using CS/MG2)
# Posted By doug sims | 3/14/07 12:05 PM
Hi Ray,

About exporting (I just figured out), you can export a clean directory tree from a working copy, as well as from a repository location.

Using TortoiseSVN's context menu from the working folder, then export to some other new folder elsewhere, exporting unversioned files too.

Command line is "export PATH1 PATH2" instead of "export URL PATH"
# Posted By David Lakein | 3/22/07 2:35 PM