Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Web Development

1802 Articles
article-image-phx-place-holders-extended-modx
Packt
28 Oct 2009
4 min read
Save for later

PHx (Place Holders extended) in MODx

Packt
28 Oct 2009
4 min read
PHx in action Let us learn our need of PHx by building a new functionality for our site that lets us add profiles of our family members and friends. We will add a new page called 'Family and Friends' that will show the list of all the individuals that we add. Once the user clicks on an individual, it will show certain details such as name, relationship to you, occupation, web site. This is easy to implement; all we have to do is create the template variables for each of the fields, and create a template that uses these template variables. So, to display the Occupation, the template will have a code similar to the following: Occupation: [*occupation*] Though this might appear to work initially, it has a small glitch in it. When we are entering the personal details of an individual, we may not want to enter all of the values for every individual. In the case of not having a value for the variable, it looks cleaner to not show the label at all instead of leaving it blank. In our case—if we have no value for occupation—it will look cleaner to not show the label Occupation. So here comes a need for displaying certain text only if the template variable—in this case, occupation—has a value. We can do this using PHx without having to write a snippet. Installing PHx To download PHx, use the following steps: Download PHx from http://MODxcms.com/PHx-1006.html. Extract the contents of the downloaded file. Create a directory called phx in the assets/plugins folder of your MODx installation. Copy all the files within the extracted folder to the assets/plugins/phx folder. Create a new plug-in using the MODx Manager interface: Click on the Manage Resources menu item in the Resources menu Click on the Plugins tab Click on the New Plugin link Fill it with the following details: Field Name Field Value Plugin Name PHx Plugin Code Contents of the file phx.plugin.txt in the extracted folder System Events | OnParseDocument Checked      6.Click on Save. Adding Family and Friends documents Let us create a page that lists all the members from the Family or Friends group. This document will be a container that will have a document for each member that you would like to add. Hence, just as you have learned earlier, a call to the Ditto snippet can get you all the documents that a container holds. Create a page with the following details: Field Name Field Value Title Family and Friends Uses template Learning MODx default template Modify the page created in the previous step to have the following code. (Note that we need to know the ID of the created page for the code and hence, we are modifying it after creating it.) <ul> [!Ditto? &parents=`65` &tpl=`familyandfriendslist`!]</ul> Here, 65 is the ID of the created document. We give the ID of this document here as we will be adding the other documents as child documents of this document. In the above Ditto call, we have indicated that we are using a custom chunk to control the appearance of the listing. Create a chunk with the following details, to show a neat list of the documents that represent a member with the title and a link to the document. Field Name Field Value Chunk name familyandfriendslist Existing Category Learning MODx Chunk Code <li> <h3><a href="[~[+id+]~]">[+title+]</a></h3> </li>  
Read more
  • 0
  • 0
  • 1561

article-image-how-bridge-client-server-gap-using-ajax-part-i
Packt
28 Oct 2009
18 min read
Save for later

How to Bridge the Client-Server Gap using AJAX (Part I)

Packt
28 Oct 2009
18 min read
Technically, AJAX is an acronym standing for Asynchronous JavaScript and XML. The technologies involved in an AJAX solution include: JavaScript, to capture interactions with the user or other browser-related events The XMLHttpRequest object, which allows requests to be made to the server without interrupting other browser tasks XML files on the server, or often other similar data formats such as HTML or JSON More JavaScript, to interpret the data from the server and present it on the page Many frameworks have sprung up to assist developers in taming it, because of the inconsistencies in the browsers' implementations of the XMLHttpRequest object; jQuery is no exception. Let us see if AJAX can truly perform miracles. Loading data on demand Underneath all the hype and trappings, AJAX is just a means of loading data from the server to the web browser, or client, without a visible page refresh. This data can take many forms, and we have many options for what to do with it when it arrives. We'll see this by performing the same basic task in many ways. We are going to build a page that displays entries from a dictionary, grouped by the starting letter of the dictionary entry. The HTML defining the content area of the page will look like this: <div id="dictionary"></div> Yes, really! Our page will have no content to begin with. We are going to use jQuery's various AJAX methods to populate this <div> with dictionary entries. <div class="letters"> <div class="letter" id="letter-a"> <h3><a href="#">A</a></h3> </div> <div class="letter" id="letter-b"> <h3><a href="#">B</a></h3> </div> <div class="letter" id="letter-c"> <h3><a href="#">C</a></h3> </div> <div class="letter" id="letter-d"> <h3><a href="#">D</a></h3> </div></div> As always, a real-world implementation should use progressive enhancement to make the page function without requiring JavaScript. Here, to simplify our example, the links do nothing until we add behaviors to them with jQuery. As always, a real-world implementation should use progressive enhancement to make the page function without requiring JavaScript. Here, to simplify our example, the links do nothing until we add behaviors to them with jQuery. Adding a few CSS rules, we get a page that looks like this: Now we can focus on getting content onto the page. Appending HTML AJAX applications are often no more than a request for a chunk of HTML. This technique, sometimes referred to as AHAH (Asynchronous HTTP and HTML), is almost trivial to implement with jQuery. First we need some HTML to insert, which we'll place in a file called a.html alongside our main document. This secondary HTML file begins: <div class="entry"> <h3 class="term">ABDICATION</h3> <div class="part">n.</div> <div class="definition"> An act whereby a sovereign attests his sense of the high temperature of the throne. <div class="quote"> <div class="quote-line">Poor Isabella's Dead, whose abdication</div> <div class="quote-line">Set all tongues wagging in the Spanish nation.</div> <div class="quote-line">For that performance 'twere unfair to scold her:</div> <div class="quote-line">She wisely left a throne too hot to hold her.</div> <div class="quote-line">To History she'll be no royal riddle &mdash;</div> <div class="quote-line">Merely a plain parched pea that jumped the griddle.</div> <div class="quote-author">G.J.</div> </div> </div></div><div class="entry"> <h3 class="term">ABSOLUTE</h3> <div class="part">adj.</div> <div class="definition"> Independent, irresponsible. An absolute monarchy is one in which the sovereign does as he pleases so long as he pleases the assassins. Not many absolute monarchies are left, most of them having been replaced by limited monarchies, where the sovereign's power for evil (and for good) is greatly curtailed, and by republics, which are governed by chance. </div></div> The page continues with more entries in this HTML structure. Rendered on its own, this page is quite plain:   Note that a.html is not a true HTML document; it contains no <html>, <head>, or <body>, all of which are normally required. We usually call such a file a snippet or fragment; its only purpose is to be inserted into another HTML document, which we'll accomplish now: $(document).ready(function() { $('#letter-a a').click(function() { $('#dictionary').load('a.html'); return false; });}); The .load() method does all our heavy lifting for us! We specify the target location for the HTML snippet by using a normal jQuery selector, and then pass the URL of the file to be loaded as a parameter to the method. Now, when the first link is clicked, the file is loaded and placed inside <div id="dictionary">. The browser will render the new HTML as soon as it is inserted:   Note that the HTML is now styled, whereas before it was plain. This is due to the CSS rules in the main document; as soon as the new HTML snippet is inserted, the rules apply to its tags as well. When testing this example, the dictionary definitions will probably appear instantaneously when the button is clicked. This is a hazard of working on our applications locally; it is hard to account for delays in transferring documents across the network. Suppose we added an alert box to display after the definitions are loaded: $(document).ready(function() { $('#letter-a a').click(function() { $('#dictionary').load('a.html'); alert('Loaded!'); return false; });}); However, when this particular code is tested on a production web server, the alert will quite possibly have come and gone before the load has completed, due to network lag. This happens because all AJAX calls are by default asynchronous. Otherwise, we'd have to call it SJAX, which hardly has the same ring to it! Asynchronous loading means that once the HTTP request to retrieve the HTML snippet is issued, script execution immediately resumes without waiting. Sometime later, the browser receives the response from the server and handles it. This is generally desired behavior; it is unfriendly to lock up the whole web browser while waiting for data to be retrieved. If actions must be delayed until the load has been completed, jQuery provides a callback for this. An example will be provided below.   Working with JavaScript objects Pulling in fully-formed HTML on demand is very convenient, but there are times when we want our script to be able to do some processing of the data before it is displayed. In this case, we need to retrieve the data in a structure that we can traverse with JavaScript. With jQuery's selectors, we could traverse the HTML we get back and manipulate it, but it must first be inserted into the document. A more native JavaScript data format can mean even less code. Retrieving a JavaScript object As we have often seen, JavaScript objects are just sets of key-value pairs, and can be defined succinctly using curly braces ({}). JavaScript arrays, on the other hand, are defined on the fly with square brackets ([]). Combining these two concepts, we can easily express some very complex and rich data structures. The term JavaScript Object Notation (JSON) was coined by Douglas Crockford to capitalize on this simple syntax. This notation can offer a concise alternative to the sometimes-bulky XML format: { "key": "value", "key 2": [ "array", "of", "items" ]} For information on some of the potential advantages of JSON, as well as implementations in many programming languages, visit http://json.org/ . We can encode our data using this format in many ways. We'll place some dictionary entries in a JSON file we'll call b.json, which begins as follows: [ { "term": "BACCHUS", "part": "n.", "definition": "A convenient deity invented by the...", "quote": [ "Is public worship, then, a sin,", "That for devotions paid to Bacchus", "The lictors dare to run us in,", "And resolutely thump and whack us?" ], "author": "Jorace" }, { "term": "BACKBITE", "part": "v.t.", "definition": "To speak of a man as you find him when..." }, { "term": "BEARD", "part": "n.", "definition": "The hair that is commonly cut off by..." }, To retrieve this data, we'll use the $.getJSON() method, which fetches the file and processes it, providing the calling code with the resulting JavaScript object. Global jQuery functions To this point, all jQuery methods that we've used have been attached to a jQuery object that we've built with the $() factory function. The selectors have allowed us to specify a set of DOM nodes to work with, and the methods have operated on them in some way. This $.getJSON() function, however, is different. There is no logical DOM element to which it could apply; the resulting object has to be provided to the script, not injected into the page. For this reason, getJSON() is defined as a method of the global jQuery object (a single object called jQuery or $ defined once by the jQuery library), rather than of an individual jQuery object instance (the objects we create with the $() function). If JavaScript had classes like other object-oriented languages, we'd call $.getJSON() a class method. For our purposes, we'll refer to this type of method as a global function; in effect, they are functions that use the jQuery namespace so as not to conflict with other function names. To use this function, we pass it the file name as before: $(document).ready(function() { $('#letter-b a').click(function() { $.getJSON('b.json'); return false; });}); This code has no apparent effect when we click the link. The function call loads the file, but we have not told JavaScript what to do with the resulting data. For this, we need to use a callback function. The $.getJSON() function takes a second argument, which is a function to be called when the load is complete. As mentioned before, AJAX calls are asynchronous, and the callback provides a way to wait for the data to be transmitted rather than executing code right away. The callback function also takes an argument, which is filled with the resulting data. So, we can write: $(document).ready(function() { $('#letter-b a').click(function() { $.getJSON('b.json', function(data) { }); return false; });}); Here we are using an anonymous function as our callback, as has been common in our jQuery code for brevity. A named function could equally be provided as the callback. Inside this function, we can use the data variable to traverse the data structure as necessary. We'll need to iterate over the top-level array, building the HTML for each item. We could do this with a standard for loop, but instead we'll introduce another of jQuery's useful global functions, $.each(). Instead of operating on a jQuery object, this function takes an array or map as its first parameter and a callback function as its second. Each time through the loop, the current iteration index and the current item in the array or map are passed as two parameters to the callback function. $(document).ready(function() { $('#letter-b a').click(function() { $.getJSON('b.json', function(data) { $('#dictionary').empty(); $.each(data, function(entryIndex, entry) { var html = '<div class="entry">'; html += '<h3 class="term">' + entry['term'] + '</h3>'; html += '<div class="part">' + entry['part'] + '</div>'; html += '<div class="definition">'; html += entry['definition']; html += '</div>'; html += '</div>'; $('#dictionary').append(html); }); }); return false; });}); Before the loop, we empty out <div id="dictionary"> so that we can fill it with our newly-constructed HTML. Then we use $.each() to examine each item in turn, building an HTML structure using the contents of the entry map. Finally, we turn this HTML into a DOM tree by appending it to the <div>. This approach presumes that the data is safe for HTML consumption; it should not contain any stray < characters, for example. All that's left is to handle the entries with quotations, which takes another $.each() loop: $(document).ready(function() { $('#letter-b a').click(function() { $.getJSON('b.json', function(data) { $('#dictionary').empty(); $.each(data, function(entryIndex, entry) { var html = '<div class="entry">'; html += '<h3 class="term">' + entry['term'] + '</h3>'; html += '<div class="part">' + entry['part'] + '</div>'; html += '<div class="definition">'; html += entry['definition']; if (entry['quote']) { html += '<div class="quote">'; $.each(entry['quote'], function(lineIndex, line) { html += '<div class="quote-line">' + line + '</div>'; }); if (entry['author']) { html += '<div class="quote-author">' + entry['author'] + '</div>'; } html += '</div>'; } html += '</div>'; html += '</div>'; $('#dictionary').append(html); }); }); return false; });}); With this code in place, we can click the B link and confirm our results:   The JSON format is concise, but not forgiving. Every bracket, brace, quote, and comma must be present and accounted for, or the file will not load. In most browsers, we won't even get an error message; the script will just silently fail. Executing a script Occasionally we don't want to retrieve all the JavaScript we will need when the page is first loaded. We might not know what scripts will be necessary until some user interaction occurs. We could introduce <script> tags on the fly when they are needed, but a more elegant way to inject additional code is to have jQuery load the .js file directly. Pulling in a script is about as simple as loading an HTML fragment. In this case, we use the global function $.getScript(), which, like its siblings, accepts a URL locating the script file: $(document).ready(function() { $('#letter-c a').click(function() { $.getScript('c.js'); return false; });}); Scripts fetched in this way are run in the global context of the current page. This means they have access to all globally-defined functions and variables, notably including jQuery itself. We can therefore mimic the JSON example to prepare and insert HTML on the page when the script is executed, and place this code in c.js:. var entries = [ { "term": "CALAMITY", "part": "n.", "definition": "A more than commonly plain and..." }, { "term": "CANNIBAL", "part": "n.", "definition": "A gastronome of the old school who..." }, { "term": "CHILDHOOD", "part": "n.", "definition": "The period of human life intermediate..." }, { "term": "CLARIONET", "part": "n.", "definition": "An instrument of torture operated by..." }, { "term": "COMFORT", "part": "n.", "definition": "A state of mind produced by..." }, { "term": "CORSAIR", "part": "n.", "definition": "A politician of the seas." }];var html = '';$.each(entries, function() { html += '<div class="entry">'; html += '<h3 class="term">' + this['term'] + '</h3>'; html += '<div class="part">' + this['part'] + '</div>'; html += '<div class="definition">' + this['definition'] + '</div>'; html += '</div>';});$('#dictionary').html(html); Now clicking on the C link has the expected result: Loading an XML document XML is part of the acronym AJAX, but we haven't actually loaded any XML yet. Doing so is straightforward, and mirrors the JSON technique fairly closely. First we'll need an XML file d.xml containing some data we wish to display, excerpted here: <?xml version="1.0" encoding="UTF-8"?><entries> <entry term="DEFAME" part="v.t."> <definition> To lie about another. To tell the truth about another. </definition> </entry> <entry term="DEFENCELESS" part="adj."> <definition> Unable to attack. </definition> </entry> <entry term="DELUSION" part="n."> <definition> The father of a most respectable family, comprising Enthusiasm, Affection, Self-denial, Faith, Hope, Charity and many other goodly sons and daughters. </definition> <quote author="Mumfrey Mappel"> <line>All hail, Delusion! Were it not for thee</line> <line>The world turned topsy-turvy we should see; </line> <line>For Vice, respectable with cleanly fancies, </line> <line>Would fly abandoned Virtue's gross advances. </line> </quote> </entry> <entry term="DIE" part="n."> <definition> The singular of "dice." We seldom hear the word, because there is a prohibitory proverb, "Never say die." At long intervals, however, some one says: "The die is cast," which is not true, for it is cut. The word is found in an immortal couplet by that eminent poet and domestic economist, Senator Depew: </definition> <quote> <line>A cube of cheese no larger than a die</line> <line>May bait the trap to catch a nibbling mie.</line> </quote> </entry></entries> This data could be expressed in many ways, of course, and some would more closely mimic the structure we established for the HTML or JSON used earlier. Here, however, we're illustrating some of the features of XML designed to make it more readable to humans, such as the use of attributes for term and part rather than tags. $(document).ready(function() { $('#letter-d a').click(function() { $.get('d.xml', function(data) { }); return false; });}); This time it's the $.get() function that does our work. In general, this function simply fetches the file at the supplied URL and provides the plain text to the callback. However, if the response is known to be XML because of its server-supplied MIME type, the callback will be handed the XML DOM tree. Fortunately, as we have already seen, jQuery has substantial DOM traversing capabilities. We can use the normal .find(), .filter() and other traversal methods on the XML document just as we would on HTML: $(document).ready(function() { $('#letter-d a').click(function() { $.get('d.xml', function(data) { $('#dictionary').empty(); $(data).find('entry').each(function() { var $entry = $(this); var html = '<div class="entry">'; html += '<h3 class="term">' + $entry.attr('term') + '</h3>'; html += '<div class="part">' + $entry.attr('part') + '</div>'; html += '<div class="definition">'; html += $entry.find('definition').text(); var $quote = $entry.find('quote'); if ($quote.length) { html += '<div class="quote">'; $quote.find('line').each(function() { html += '<div class="quote-line">' + $(this).text() + '</div>'; }); if ($quote.attr('author')) { html += '<div class="quote-author">' + $quote.attr('author') + '</div>'; } html += '</div>'; } html += '</div>'; html += '</div>'; $('#dictionary').append($(html)); }); }); return false; });}); This has the expected effect when the D link is clicked: This is a new use for the DOM traversal methods we already know, shedding some light on the flexibility of jQuery's CSS selector support. CSS syntax is typically used to help beautify HTML pages, and thus selectors in standard .css files use HTML tag names such as div and body to locate content. However, jQuery can use arbitrary XML tag names, such as entry and definition here, just as readily as the standard HTML ones. The advanced selector engine inside jQuery facilitates finding parts of the XML document in much more complicated situations, as well. For example, suppose we wanted to limit the displayed entries to those that have quotes that in turn have attributed authors. To do this, we can limit the entries to those with nested <quote> elements by changing entry to entry:has(quote). Then we can further restrict the entries to those with author attributes on the <quote> elements by writing entry:has(quote[author]). The line with the initial selector now reads: $(data).find('entry:has(quote[author])').each(function() { This new selector expression restricts the returned entries correspondingly:    
Read more
  • 0
  • 0
  • 2659

article-image-managing-manufacturers-vendors-and-product-categories-joomla-e-commerce-virtuemart
Packt
28 Oct 2009
7 min read
Save for later

Managing Manufacturers, Vendors, and Product Categories with Joomla! E-Commerce VirtueMart

Packt
28 Oct 2009
7 min read
We are going to add and edit a lot of information for manufacturers, vendors, and product categories. Actually, in this article, our VirtueMart shop will really take shape with products we want to sell. Catalogue management The product catalog for an online shop comprises of the products we sell in the shop. Whatever products we want to sell should be added to this product catalog first. Once products are added to the catalog, customers can browse the products and decide to buy whatever they need. Therefore, managing the catalog is one of the primary tasks of the shop owner. Products that we add to the catalog need to be organized to help customers easily find the right products. In VirtueMart, customers can sort the products by product categories and manufacturers. Therefore, before adding products to the catalog, we will look into managing manufacturers and product categories. Managing manufacturers In VirtueMart, whenever we add a product to the catalog, we also need to assign a manufacturer for that product. In reality, every product has a manufacturer, and for better management of the shop, we should be able to find products by their manufacturer. Therefore, first step will be to identify the manufacturers and enter their information in VirtueMart store. We can also categorize the manufactures as publishers, software developers, and so on. Adding a manufacturer category There is a default manufacturer category for use in VirtueMart. We can use that default category for creating a manufacturer. However, when we are selling large number of products from a large number of manufacturers, classifying them into categories will be convenient for managing the manufacturers. For adding a manufacturer, in the VirtueMart administration panel, click on Manufacturer | Add Manufacturer Category. This shows Manufacturer Category Form: In the Manufacturer Category Form, provide information for the Category Name and the Category Description fields. Once these are provided, click the Save icon in the toolbar to save the manufacturer category. In the same process, you can add as many categories as you want. Adding a manufacturer For adding a manufacturer, in the VirtueMart administration panel, select Manufacturer | Add Manufacturer. This shows Add Information screen: In the Add Information screen, type the manufacturer's name, their URL, email address, and a brief description. In the Manufacturer Category field, select the category. The drop-down list will show the manufacturer categories you created earlier. Once all the information is provided in this screen, click the Save icon in the toolbar to save the manufacturer information. Listing the manufacturer categories Once you have added the manufacturer categories, you can view the list of manufacturer categories by selecting Manufacturer | List Manufacturer Categories. This shows Manufacturer Category List screen: In the Manufacturer Category List screen, you will see all manufacturer categories you have created. From this screen, you can add a new category by clicking the New icon in the toolbar. Similarly, you can remove a category by clicking on the trash icon in Remove column, or by selecting the categories and clicking the Remove icon in the toolbar. You can edit a category by clicking on the category name. To view the list of manufacturers, click on the Manufacturer List link in the Manufacturers column, or select Manufacturer | List Manufacturers. This shows Manufacturer List screen displaying all manufacturers you have added: From the Manufacturer List screen, you can create a new manufacturer, remove one or more manufacturers, and edit any manufacturer. For editing a manufacturer, click on the manufacturer's name or the Update link in Admin column. This will bring up the Add Information screen again. You can also create a new manufacturer by clicking the New icon in the toolbar. From the Manufacturer Category List screen, you may think that clicking on the Manufacturer List link against each category will display the manufacturers added to that category only. Ideally, this should be the case. However, until VirtueMart 1.1.2, it shows the list of manufacturers from all the categories. We hope this will be fixed in the upcoming releases of VirtueMart. Managing vendors The idea of multiple vendors is something what you can see on Amazon.com. Different vendors add their products to sell, when the order is placed, the store notifies the vendor to fulfill the order. The main store usually gets a commission from the vendor for each sell made through the store. However, VirtueMart's vendors feature is still in its infancy and does not yet function properly. You can add multiple vendors in VirtueMart, and assign products to the vendors. However, adding vendors has no effect on selling any product on the VirtueMart store, except when applying different vendor-specific tax rates and shopper groups. At the moment, it also helps to identify products from different vendors. In the following sections, you will see how to add and manage vendors. Vendor category Like manufacturers, you can also create vendor categories. For creating vendor categories, go to Vendor | Add Vendor Category. This displays Vendor Category Form: In the Vendor Category Form, type the name of the category and its description. Then click the Save icon in the toolbar. You can add as many categories as you want. Before trying to add vendor categories, first plan how you are going to categorize your vendors (for example, based on the product they sell or their location). Have a full category tree on hand and then start creating categories. Adding vendor Once you have created the necessary vendor categories, you can proceed to adding vendors. For adding vendors, click on Vendor | Add Vendor. This displays the Add Information screen: CautionNote that there is a warning sign at the top of Add Information screen. It warns you about using the vendor feature as it is in the 'Alpha' or pre-mature stage. Also note that we have used Simple Layout for displaying it. If you try adding a vendor from Extended Layout, you will open up an edit screen for existing vendor information, which you already added during the initial configuration of the shop. Up until VirtueMart 1.1.2, a bug has been encountered and which will hopefully be fixed in future releases when it crosses 'Alpha' stage. The Add Information screen shows three tabs: Store, Store Information, and Contact Information. From the Store tab, add the vendor's store name, company name, logo, web site URL, minimum purchase order value, and minimum amount for free shipping. You can also configure the currency symbol, decimal points, decimal symbol, thousand separator, positive format, and negative format. In the Store Information tab (seen in the previous screenshot), you can add the address of the store, city, state/province/region, zip/postal code, phone, currency and vendor category. The vendor categories you have created earlier will be available in Vendor Category drop-down list. In the Contact Information tab (seen in the previous screenshot), you can set the contact details of the vendor, such as name, title, phone, fax, email. You can also add a brief description of the vendor which will be displayed in the vendor details page in the store. Type a brief description in the Description rich-text editing box. In the Terms of Service rich-text editing box, provide terms of service applicable for that vendor. Once information in all the three tabs are provided, click the Save icon in the toolbar to add the vendor.
Read more
  • 0
  • 0
  • 4367

article-image-elgg-social-networking-installation
Packt
28 Oct 2009
14 min read
Save for later

Elgg Social Networking - Installation

Packt
28 Oct 2009
14 min read
Installing Elgg In addition to its impressive feature list, Elgg is an admin's dolly. In this tutorial by Mayank Sharma, we will see how Elgg can be installed in popular Linux web application rollout stack of Linux, Apache, MySQL, and PHP, fondly referred to as LAMP. As MySQL and PHP can run under Windows operating system as well, you can set up Elgg to serve your purpose for such an environment. Setting Up LAMP Let's look at setting up the Linux, Apache, MySQL, PHP web server environment. There are several reasons for the LAMP stack's popularity. While most people enjoy the freedom offered by these Open Source software, small business and non-profits will also be impressed by its procurement cost—$0. Step 1: Install Linux The critical difference between setting up Elgg under Windows or Linux is installing the operating system. The Linux distribution I'm using to set up Elgg is Ubuntu Linux ( http://www.ubuntu.com/ ).It's available as a free download and has a huge and active global community, should you run into any problems. Covering step-by-step installation of Ubuntu Linux is too much of a digression for this tutorial. Despite the fact that Ubuntu isn't too difficult to install, because of its popularity there are tons of installation and usage documentation available all over the Web. Linux.com has a set of videos that detail the procedure of installing Ubuntu ( http://www.linux.com/articles/114152 ).Ubuntu has a dedicated help section ( https://help.ubuntu.com/ ) for introduction and general usage of the distribution. Step 2: Install Apache Apache is the most popular web server used on the Internet. Reams and reams of documents have been written on installing Apache under Linux. Apache's documentation sub-project ( http://httpd.apache.org/docs-project/ ) has information on installing various versions of Apache under Linux. Ubuntu, based on another popular Linux distribution, Debian, uses a very powerful and user-friendly packaging system. It's called apt-get and can install an Apache server within minutes. All you have to do is open a terminal and write this command telling apt-get what to install: apt-get install apache2 apache2-common apache2-doc apache2-mpm-prefork apache2-utils libapr0 libexpat1 ssl-cert This will download Apache and its most essential libraries. Next, you need to enable some of Apache's most critical modules: a2enmod ssla2enmod rewritea2enmod include The rewrite module is critical to Elgg, so make sure it's enabled, else Elgg wouldn't work properly. That's it. Now, just restart Apache with: /etc/init.d/apache2 restart. Step 3: MySQL Installing MySQL isn't too much of an issue either. Again, like Ubuntu and Apache, MySQL can also boast of a strong and dedicated community. This means there's no dearth of MySQL installation or usage related documentation ( http://www.mysql.org/doc/ ). If you're using MySQL under Ubuntu, like me, installation is just a matter of giving apt-get a set of packages to install: apt-get install mysql-server mysql-client libmysqlclient12-dev Finally, set up a password for MySQL with: mysqladmin -h yourserver.example.com -u root password yourrootmysqlpassword Step 4: Install PHP Support You might think I am exaggerating things a little bit here, but I am not, PHP is one of the most popular and easy to learn languages for writing web applications. Why do you think we are setting up out Linux web server environment to execute PHP? It's because Elgg itself is written in PHP! And so are hundreds and thousands of other web applications. So I'm sure you've guessed by now that PHP has a good deal of documentation ( http://www.php.net/docs.php )as well. You've also guessed it's now time to call upon Ubuntu's apt-get package manager to set up PHP:  apt-get install libapache2-mod-php5 php5 php5-common php5-gd php5-mysql php5-mysqli As you can see, in addition to PHP, we are also installing packages that'll hook up PHP with the MySQL database and the Apache web server. That's all there is to setting up the LAMP architecture to power your Elgg network. Setting Up WAMP If you are used to Microsoft's Windows operating system or want to avoid the extra minor learning curve involved with setting up the web server on a Linux distribution, especially, if you haven't done it before, you can easily replicate the Apache, MySQL, PHP web server on a Windows machine. Cost wise, all server components the Apache web server, MySQL database, and the PHP development language have freely available Windows versions as well. But the base component of this stack, the operating system —Microsoft Windows, isn't. Versions of Apache, MySQL, and PHP for Windows are all available on the same websites mentioned above. As Windows doesn't have an apt-get kind of utility, you'll have to download and install all three components from their respective websites, but you have an easier way to set up a WAMP server. There are several pre-packaged Apache, MySQL, and PHP software bundles available for Windows(http://en.wikipedia.org/wiki/Comparison_of_WAMPs).I've successfully run Elgg on the WAMP5 bundle (http://www.en.wampserver.com/). The developer updates the bundle, time and again, to make sure it's running the latest versions of all server components included in the bundle. Note - While WAMP5 requires no configuration, make sure you have Apache's rewrite_module and PHP's php_gd2 extension enabled. They will have a bullet next to their name if they are enabled. If the bullet is missing, click on the respective entries under the Apache and PHP sub-categories and restart WAMP5. Installing Elgg Now that we have a platform ready for Elgg, let's move on to the most important step of setting up Elgg. Download the latest version of Elgg from its website. At the time of writing this tutorial, the latest version of Elgg was Elgg-0.8. Elgg is distributed as a zipped file. To uncompress under Linux: Move this zipped file to /tmp and uncompress it with the following command: $ unzip /tmp/elgg-0.8.zip To uncompress under Windows: Right-click on the ZIP file and select the Extract here option. After uncompressing the ZIP file, you should have a directory called Elgg-<version-number>, in my case, elgg-0.8/. This directory contains several sub directories and files. The INSTALL file contains detailed installation instructions. The first step is to move this uncompressed directory to your web server. Note: You can set up Elgg on your local web server that sits on the Internet or on a paid web server in a data center anywhere on the planet. The only difference between the two setups is that if you don't have access to the local web server, you'll have to contact the web service provider and ask him about the transfer options available to you. Most probably, you'll have FTP access to your web server, and you'll have to use one of the dozens of FTP clients, available for free, to transfer Elgg's files from your computer to the remote web server. Optionally, if you have "shell" access on the web server, you might want to save time by transferring just the zipped file and unzipping it on the web server itself. Contact your web server provider for this information. The web server's directory where you need to copy the contents of the Elgg directory depends upon your Apache installation and operating system. In Ubuntu Linux, the default web server directory is /var/www/. In Windows, WAMP5 asks where it should create this directory during installation. By default, it's the www directory and is created within the directory you installed WAMP5 under. Note: Another important decision you need to make while installing Elgg is how do you want your users to access your network. If you're setting up the network to be part of your existing web infrastructure, you'll need to install Elgg inside a directory. If, on the other hand, you are setting up a new site just for the Elgg-powered social network, copy the contents of the Elgg directory inside the www directory itself and not within a subdirectory. Once you have the Elgg directory within your web server's www directory, it's time to set things in motion. Start by renaming the config-dist.php file to config.php and the htaccess-dist to .htaccess. Simply right-click on the file and give it a new name or use the mv command in this format: $ mv <original-file-name> <new-file-name> Note : To rename htacces-dist to .htaccess in Windows, you'll have to open the htaccess-dist file in notepad and then go to File | Save As and specify the name as .htaccess with the quotes. Editing config.php Believe it or not, we've completed the "installation" bit of setting up Elgg. But we still need to configure it before throwing the doors open to visitors. Not surprisingly, all this involves is creating a database and editing the config.php file to our liking. Creating a Database Making an empty database in MySQL isn't difficult at all. Just enter the MySQL interactive shell using your username, password, and hostname you specified while installing MySQL. $ mysql -u root -h localhost -pEnter password: Welcome to the MySQL monitor. Commands end with ; or g.Your MySQL connection id is 9 to server version: 5.0.22-Debian_0ubuntu6.06.3-logType 'help;' or 'h' for help. Type 'c' to clear the buffer.mysql> CREATE DATABASE elgg; You can also create a MySQL database using a graphical front-end manager like PHPMyAdmin, which comes with WAMP5. Just look for a database field, enter a new name (Elgg), and hit the Create button to create an empty Elgg database. Initial Configuration Elgg has a front-end interface to set up config.php, but there are a couple of things you need to do before you can use that interface: Create a data directory outside your web server root. As described in the configuration file, this is a special directory where uploaded files will go. It's also advisable to create this directory outside your main Elgg install. This is because this directory will be writable by everyone accessing the Elgg site and having such a "world-accessible" directory under your Elgg installation is a security risk. If you call the directory Elgg-data, make it world-readable with the following command: $ chmod 777 elgg-data Setup admin username and password. Before you can access Elgg's configuration web front-end, you need an admin user and a password. For that open the config.php file in your favorite text editor and scroll down to the following variables: $CFG->adminuser = "";$CFG->adminpassword = ""; Specify your chosen admin username and password between the quotes, so that it looks something like this: $CFG->adminuser = "admin";$CFG->adminpassword = "765thyr3"; Make sure you don't forget the username and password of the admin user. Important Settings When you have created the data directory and specified an admin username and password, it's time to go ahead with the rest of the configuration. Open a web browser and point to http://<your-web-server>/<Elgg-installation>/elggadmin/ This will open up a simple web page with lots of fields. All fields have a title and a brief description of the kind of information you need to fill in that field. There are some drop-down lists as well, from which you have to select one of the listed options. Here are all the options and their descriptions: Administration panel username: Username to log in to this admin panel, in future, to change your settings. Admin password: Password to log in to this admin panel in future. Site name: Enter the name of your site here (e.g. Elgg, Apcala, University of Bogton's Social Network, etc.). Tagline: A tagline for your site (e.g. Social network for Bogton). Web root: External URL to the site (e.g. http://elgg.bogton.edu/). Elgg install root: Physical path to the files (e.g./home/Elggserver/httpdocs/). Elgg data root: This is a special directory where uploaded files will go. If possible, this should live outside your main Elgg installation? (you'll need to create it by hand). It must have world writable permissions set, and have a final slash at the end. Note: Even in Windows, where we use back slashes () to separate directories, use Unix's forward slashes (/) to specify the path to the install root, data root, and other path names. For example, if you have Elgg files under WAMP's default directory in your C drive, use this path: C:/wamp/www/elgg/. Database type: Acceptable values are mysql and postgres - MySQL is highly recommended. System administrator email: The email address your site will send emails from(e.g. elgg-admin@bogton.edu). News account initial password: The initial password for the 'news' account. This will be the first administrator user within your system, and you should change the password immediately after the first time you log in. Default locale: Country code to set language to if you have gettext installed. Public registration: Can general members of the public register for this system? Public invitations: Can users of this system invite other users? Maximum users: The maximum number of users in your system. If you set this to 0, you will have an unlimited number of users. Maximum disk space: The maximum disk space taken up by all uploaded files. Disable public comments: Set the following to true to force users to log in before they can post comments, overriding the per-user option. This is a handy sledgehammer-to-crack-a-nut tactic to protect against comment spam (although an Akismet plug-in is available from elgg.org). Email filter: Anything you enter here must be present in the email address of anyone who registers; e.g. @mycompany.com will only allow email address from mycompany.com to register. Default access: The default access level for all new items in the system. Disable user templates: If this is set, users can only choose from available templates rather than defining their own. Persistent connections: Should Elgg use persistent database connections? Debug: Set this to 2047 to get ADOdb error handling. RSS posts maximum age: Number of days for which to keep incoming RSS feed entries before deleting them. Set this to 0 if you don't want RSS posts to be removed. Community create flag: Set this to admin if you would like to restrict the ability to create communities to admin users. cURL path: Set this to the cURL executable if cURL is installed; otherwise leave blank. Note : According to Wikipedia, cURL is a command line tool for transferring files with URL syntax, supporting FTP, FTPS, HTTP, HTTPS, TFTP, SCP,SFTP, Telnet, DICT, FILE, and LDAP. The main purpose and use for cURL is to automate unattended file transfers or sequences of operations. For example, it is a good tool for simulating a user's actions at a web browser. Under Ubuntu Linux, you can install curl using the following command: apt-get install curl Templates location: The full path of your Default_Template directory. Profile location: The full path to your profile configuration file (usually, it's best to leave this in mod/profile/). Finally, when you're done, click on the Save button to save the settings. Note : The next version of Elgg, Elgg 0.9, will further simplify installation. Already an early release candidate of this version (elgg-0.9rc1) is a lot more straightforward to install and configure, for initial use. First Log In Now, it's time to let Elgg use these settings and set things up for you. Just point your browser to your main Elgg installation (http://<your-web-servergt;/<Elgg-installation>). It'll connect to the MySQL database and create some tables, then upload some basic data, before taking you to the main page. On the main page, you can use the news account and the password you specified for this account during configuration to log in to your Elgg installation.
Read more
  • 0
  • 0
  • 16066

article-image-customizing-elgg-themes
Packt
27 Oct 2009
8 min read
Save for later

Customizing Elgg Themes

Packt
27 Oct 2009
8 min read
Why Customize? Elgg ships with a professional looking and slick grayish-blue default theme. Depending on how you want to use Elgg, you'd like your network to have a personalized look. If you are using the network for your own personal use, you really don't care a lot about how it looks. But if you are using the network as part of your existing online infrastructure, would you really want it to look like every other default Elgg installation on the planet? Of course not! Visitors to your network should easily identify your network and relate it to you. But theming isn't just about glitter. If you thought themes were all about gloss, think again. A theme helps you brand your network. As the underlying technology is the same, a theme is what really separates your network from the others out there. What Makes Up a Theme? There are several components that define your network. Let's take a look at the main components and some practices to follow while using them. Colors: Colors are an important part of your website's identity. If you have an existing website, you'd want your Elgg network to have the same family of colors as your main website. If the two (your website and social network) are very different, the changeover from one to another could be jarring. While this isn't necessary, maintaining color consistency is a good practice. Graphics: Graphics help you brand the network to make it your own. Every institution has a logo. Using a logo in your Elgg theme is probably the most basic change you'd want to make. But make sure the logo blends in with the theme, that is, it has the same background color. Code: It takes a little bit of HTML, a sprinkle of PHP, and some CSS magic to Code: It takes a little bit of HTML, a sprinkle of PHP, and some CSS magic to manipulate and control a theme. A CSS file: As the name suggests, this file contains all the CSS decorations. You can choose to alter colors and fonts and other elements in this file. A Pageshell file: In this pageshell file, you define the structure of your Elgg network. If you want to change the position of the Search bar or instead of the standard two-column format, move to a three-column display, this is the file you need to modify. Front page files: Two files control how the landing page of your Elgg network appears to logged out or logged in users. Optional images folder: This folder houses all the logos and other artwork that'll be directly used by the theme. Please note that this folder does not include any other graphic elements we've covered in previous tutorials such as your picture, or icons to communities, and so on. Controlling Themes Rather than being single humongous files, themes in Elgg are a bunch of small manageable files. The CSS decoration is separated from the placement code. Before getting our hands dirty creating a theme, let's take a look at the files that control the look and feel of your network. All themes must have these files: The Default Template Elgg ships with a default template that you can find under your Elgg installation. This is the structure of the files and folders that make up the default template. Before we look at the individual files and examine their contents in detail, let's first understand their content in general. All three files, pageshell, frontpage_logedin, and frontpage_loggedout are made up of two types of components. Keywords are used to pull content from the database and display them on the page. Arranging these keywords are the div<.em> and span tags along with several others like h1, ul, and so on that have been defined in the CSS file. What are <div> and <span>? The <div> and <span> are two very important tags especially when it comes to handling CSS files. In a snap, these two tags are used to style arbitrary sections of HTML. <div> does much the same thing as a paragraph tag <p>, but it divides the page up into larger sections. With <div>, you can also define the style of whole sections of HTML. This is especially useful when you want to give particular sections a different style from the surrounding text. The <span> tag is similar to the <div> tag. It is also used to change the style of the text it encloses. The difference between <span> and <div> is that a span element is in-line and usually used for a small chunk of in-line HTML. Both <div> and <span> work with two important attributes, class and id. The most common use of these containers together with the class or id attributes is when this is done with CSS to apply layout, color, and other presentation attributes to the page's content. In forthcoming sections, we'll see how the two container items use their two attributes to influence themes. The pageshell Now, let's dive into understanding the themes. Here's an exact replica of the pageshell of the Default template. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head><title>{{title}}</title> {{metatags}}</head> <body>{{toolbar}} <div id="container"><!-- open container which wraps the header, maincontent and sidebar --><div id="header"><!-- open div header --><div id="header-inner"> <div id="logo"><!-- open div logo --> <h1><a href="{{url}}">{{sitename}}</a></h1> <h2>{{tagline}}</h2> </div><!-- close div logo --> {{searchbox}}</div> </div><!-- close div header --> <div id="content-holder"><!-- open content-holder div --><div id="content-holder-inner"> <div id="splitpane-sidebar"><!-- open splitpane-sidebar div --> <ul><!-- open sidebar lists --> {{sidebar}} </ul><!-- close sidebar lists --></div><!-- close splitpane-sidebar div --> <div id="splitpane-content"><!-- open splitpane-content div --> {{messageshell}} {{mainbody}}</div><!-- close open splitpane-content div --></div> </div><!-- close content-holder div --> <div id="footer"><!-- start footer --><div id="footer-inner"><span style="color:#FF934B">{{sitename}}</span> <a href="{{url}}content/terms.php">Terms and conditions</a> | <a href="{{url}}content/privacy.php">Privacy Policy</a><br /><a href="http://elgg.org/"><img src="{{url}}mod/template/ icons/elgg_powered.png" title="Elgg powered" border="0" alt="Elgg powered"/></a><br /> {{perf}}</div> </div><!-- end footer --> </div><!-- close container div --> </body> </html> CSS Elements in the pageshell Phew! That's a lot of mumbo-jumbo. But wait a second! Don't jump to a conclusion! Browse through this section, where we disassemble the file into easy-to-understand chunks. First, we'll go over the elements that control the layout of the pageshell. <div id="container">: This container wraps the complete page and all its elements, including the header, main content, and sidebar. In the CSS file, this is defined as: div#container {width:940px;margin:0 auto;padding:0;background:#fff;border-top:1px solid #fff;} <div id="header">: This houses all the header content including the logo and search box. The CSS definition for the header element: div#header {margin:0;padding:0;text-align:left;background:url({{url}}mod/template/templates/Default_Template/images/header-bg.gif) repeat-x;position:relative;width:100%;height:120px;} The CSS definition for the logo: div#header #logo{margin: 0px;padding:10px;float:left;} The search box is controlled by the search-header element: div#header #search-header {float:right;background:url({{url}}mod/template/templates/Default_Template/images/search_icon.gif) no-repeat left top;width:330px;margin:0;padding:0;position:absolute;top:10px;right:0;} <div id="header-inner">: While the CSS file of the default template doesn't define the header-inner element, you can use it to control the area allowed to the elements in the header. When this element isn't defined, the logo and search box take up the full area of the header. But if you want padding in the header around all the elements it houses, specify that using this element. <div id="content-holder">: This wraps the main content area. #content-holder {padding:0px;margin:0px;width:100%;min-height:500px;overflow:hidden;position:relative;} <div id="splitpane-sidebar">: In the default theme, the main content area has a two-column layout, split between the content and the sidebar area. div#splitpane-sidebar {width: 220px;margin:0;padding:0;background:#fff url({{url}}mod/template/templates/Default_Template/images/side-back.gif) repeat-y;margin:0;float: right;}div#splitpane-content {margin: 0;padding: 0 0 0 10px;width:690px;text-align: left;color:#000;overflow:hidden;min-height:500px;} <div id="single-page">: While not used in the Default template, the content area can also have a simple single page layout, without the sidebar. div#single-page {margin: 0;padding: 0 15px 0 0;width:900px;text-align: left;border:1px solid #eee;} <div id="content-holder-inner">: Just like header-inner, is used only if you would like a full page layout but a defined width for the actual content. <div id="footer">: Wraps the footer of the page including the links to the terms and conditions and the privacy policy, along with the Elgg powered icon. div#footer {clear: both;position: relative;background:url({{url}}mod/template/templates/Default_Template/images/footer.gif) repeat-x top;text-align: center;padding:10px 0 0 0;font-size:1em;height:80px;margin:0;color:#fff;width:100%;} <div id="footer-inner">: Like the other inner elements, this is only used if you would like a full page layout but restrict the width for the actual footer content.
Read more
  • 0
  • 101
  • 124765

article-image-how-create-tax-rule-magento
Packt
27 Oct 2009
11 min read
Save for later

How to create a Tax Rule in Magento

Packt
27 Oct 2009
11 min read
In this article by William Rice, we will see how to create Tax Rules in Magento. In the real world, the tax rate that you pay is based on three things: location, product type, and purchaser type. In Magento, we can create Tax Rules that determine the amount of tax that a customer pays, based upon the shipping address, product class, and customer class. When you buy a product, you sometimes pay sales tax on that product. The sales tax that you pay is based on: Where you purchased the product from. Tax rules vary in different cities, states, and countries. The type of product that you purchased. For example, many places don't tax clothing purchases. And, some places tax only some kinds of clothing. This means that you must be able to apply different tax rates to different kinds of products. The type of purchaser you are. For example, if you buy a laser printer for your home, it is likely that you will pay sales tax. This is because you are a retail customer. If you buy the same printer for your business, in most places you will not pay sales tax. This is because you are a business customer. The amount of the purchase. For example, some places tax clothing purchases only above a specific amount. Anatomy of a Tax Rule A Tax Rule is a combination of the tax rate, shipping address, product class, customer class, and amount of purchase. A Tax Rule states that you pay this amount of tax if you are this class of purchaser, and you bought this class of product for this amount, and are shipping it to this place. The components of a Tax Rule are shown in the following screenshot. This screen is found under Sales | Tax | Manage Tax Rules | Add New Tax Rule. You will see the Name of the Tax Rule while working in the backend. Customer Tax Class Customer Tax Class is a type of customer that is making a purchase. Before creating a Tax Rule, you will need to have at least one Customer Tax Class. Magento provides you with a Tax Rule called Retail Customer. If you serve different types of customers—retail, business, and nonprofit—you will need to create different Customer Tax Classes. Product Tax Class Product Tax Class is a type of Product that is being purchased. When you create a Product, you will assign a Product Tax Class to that Product. Magento comes with two Product Tax Classes:Taxable Goods and Shipping. The class Shipping is applied to shipping charges because some places charge sales tax on shipping. If your customer's sales tax is different for different types of Products, then you will need to create a Product Tax Class for each type of Product. Tax Rate Tax Rate is a combination of place, or tax zone, and percentage. A zone can be a country, state, or zip code. Each zone that you specify can have up to five sales tax percentages. For example, in the default installation of Magento, there is one tax rate for the zone New York. This is 8.3750 percent, and applies to retail customers. The following window can be found at Sales | Tax | Manage Tax Zones & Rates and then clicking on US-NY-*-Rate 1: So in the screenshot of our Tax Rule, the Tax Rate US-NY-*-Rate 1 doesn't mean "a sales tax of 1 percent." It means "Tax rate number 1 for New York, which is 8.3750 percent." In this scenario, New York charges 8.3750 percent sales tax on retail sales. If New York does not charge sales tax for wholesale customers, and you sell to wholesale customers, then you will need to create another Tax Rate for New York: Whenever a zone has different sales taxes for different types of products or customers, you will need to create different Tax Rates for that zone. Priority If several Tax Rules try to apply several Tax Rates at the same time, how should Magento handle them? Should it add them all together? Or, should it apply one rate, calculate the total, and then apply the second rate to that total? That is, should Magento add them or compound them? For example, suppose you sell a product in Philadelphia, Pennsylvania. Further suppose that according to the Tax Rule for Pennsylvania, the sales tax for that item is 6 percent, and that the Tax Rule for Philadelphia adds another 1 percent. In this case, you want Magento to add the two sales taxes. So, you would give the two Tax Rates the same Priority. By contrast, Tax Rates that belong to Tax Rules with different Priorities are compounded. The Tax Rate with the higher Priority (the lower number) is applied, and the next higher Priority is applied to that total, and so on. Sort Order Sort Order determines the Tax Rules' position in the list of Tax Rules. Why create Tax Rules now? Why create a Tax Rule now, before adding our first Product? When you add a Product to your store, you put that Product into a Category, assign an Attribute Set, and select a Tax Class for that Product. By default, Magento comes with two Product Tax Classes and one Tax Rule already created. The Product Tax Classes are Taxable Goods and Shipping. The Tax Rule is Retail Customer-Taxable Goods-Rate 1. If you sell anything other than taxable goods, or sell to anyone other than retail customers, you will need to create a new Tax Rule to cover that situation. Creating a Tax Rule The process for creating a Tax Rule is: Create the Customer Tax Classes that you need, or confirm that you have them. Create the Product Tax Classes that you need, or confirm that you have them. Create the Tax Rates that you need, or confirm that you have them and that they apply to the zones that you need. Create and name the Tax Rule: Assign Customer Tax Class, Product Tax Class, and Tax Rates to the Rule. Use the Priority to determine whether the Rule is added, or compounded, with other Rules. Determine the Sort Order of the Rule and save it. Each of these steps is covered in the subsections that follow. Time for action: Creating a Customer Tax Class From the Admin Panel, select Sales | Tax | Customer Tax Classes. The Customer Tax Classes page is displayed. If this is a new installation, only one Class is listed, Retail Customer as shown in the following screenshot: Click on Add New. A Customer Tax Class Information page is displayed. Enter a name for the Customer Tax Class. In our demo store, we are going to create Customer Tax Classes for Business and Nonprofit customers. Click on Save Class. Repeat these steps until all of the Customer Tax Classes that you need have been created. What just happened? A Tax Rule is composed of a Customer Class, Product Class, Tax Rate, and the location of the purchaser. You have just created the first part of that formula: the Customer Class. Time for action: Creating a Product Tax Class From the Admin Panel, select Sales | Tax | Product Tax Classes. The Product Tax Classes page is displayed. If this is a new installation, only two Classes are listed: Shipping and Taxable Goods. Click on Add New. The Product Tax Class Information page gets displayed: Enter a name for the Product Tax Class. In our demo store, we are going to create Product Tax Classes for Food and Nonfood products. We will apply the Food class to the coffee that we sell. We will apply the Nonfood class to the mugs, coffee presses, and other coffee accessories that we sell. Click on Save Class. Repeat these steps until all of the Product Tax Classes that you need have been created. What just happened? A Tax Rule is composed of a Customer Class, Product Class, Tax Rate, and the location of the purchaser. You have just created the second part of that formula: the Product Class. Creating Tax Rates In Magento, you can create Tax Rates one at a time. You can also import Tax Rates in bulk. Each method is covered in the next section. Time for action: Creating a Tax Rate in Magento From the Admin Panel, select Sales | Tax | Manage Tax Zones & Rates. The Manage Tax Rates page is displayed. If this is a new installation, only two Tax Rates are listed: US-CA-*-Rate 1 and US-NY-*-Rate 1. Click on Add New Tax Rate. The Add New Tax Rate page gets displayed: Tax Identifier is the name that you give this Tax Rate. You will see this name when you select this Tax Rate. The example that we saw is named US-CA-*-Rate 1. Notice how this name tells you the Country, State, and Zip/Post code for the Tax Rate. (The asterisk indicates that it applies to all zip codes in California.) It also tells which rate applies. Notice that the name doesn't give the actual percentage, which is 8.25%. Instead, it says Rate 1. This is because the percentage can change when California changes its tax rate. If you include the actual rate in the name, you would need to rename this Tax Rate when California changes the rate. Another way this rate could have been named is US-CA-All- Retail. Before creating new Tax Rates, you should develop a naming scheme that works for you and your business. Country, State, and Zip/Post Code determine the zone to which this Tax Rate applies. Magento calculates sales tax based upon the billing address, and not the shipping address. Country and State are drop-down lists. You must select from the options given to you. Zip/Post Code accepts both numbers and letters. You can enter an asterisk in this field and it will be a wild card. That is, the rate will apply to all zip/post codes in the selected country and state. You can enter a zip/post code without entering a country or state. If you do this, you should be sure that zip/post code is unique in the entire world. Suppose you have one tax rate for all zip codes in a country/state, such as 6% for United States/Pennsylvania. Also, suppose that you want to have a different tax rate for a few zip codes in that state. In this case, you would create separate tax rates for those few zip codes. The rates for the specific zip codes would override the rates for the wild card. So in a Tax Rate, a wild card means, "All zones unless this is overridden by a specific zone." In our demo store, we are going to create a Tax Rate for retail customers who live in the state of Pennsylvania, but not in the city of Philadelphia as shown: Click on Save Rate. You are taken back to the Manage Tax Rates page. The Tax Rate that you just added should be listed on the page. This procedure is useful for adding Tax Rates one at a time. However, if you need to add many Tax Rates at once, you will probably want to use the Import Tax Rates feature. This enables you to import a .csv, or a text-only file. You usually create the file in a spreadsheet such as OpenOffice Calc or Excel. The next section covers importing Tax Rates. What just happened? A Tax Rule is composed of a Customer Class, Product Class, Tax Rate, and the location of the purchaser. You have just created the third part of that formula: the Tax Rate. The Tax Rate included the location and the percentage of tax. You created the Tax Rate by manually entering the information into the system, which is suitable if you don't have too many Tax Rates to type. Time for action: Exporting and importing Tax Rates In my demo store, I have created a Tax Rate for the state of Pennsylvania. The Tax Rate for the city of Philadelphia is different. However, Magento doesn't enable me to choose a separate Tax Rate based on the city. So I must create a Tax Rate for each zip code in the city of Philadelphia. At this time there are 84 zip codes, and are shown here:     19019 19092 19093 19099 19101 19102 19103 19104 19105 19106 19107 19108 19109 19110 19111 19112 19113 19114 19115 19116 19118 19119 19120 19121 19122 19123 19124 19125 19126 19127 19128 19129 19130 19131 19132 19133 19134 19135 19136 19137 19138 19139 19140 19141 19142 19143 19144 19145 19146 19147 19148 19149 19150 19151 19152 19153 19154 19155 19160 19161 19162 19170 19171 19172 19173 19175 19177 19178 19179 19181 19182 19183 19184 19185 19187 19188 19191 19192 19193 19194 19196 19197 19244 19255        
Read more
  • 0
  • 0
  • 12449
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-building-user-portal-sermyadmin-openser
Packt
27 Oct 2009
8 min read
Save for later

Building the User Portal with SerMyAdmin for OpenSER

Packt
27 Oct 2009
8 min read
SerMyAdmin Originally, this material was written for SerWeb. SerWeb was originally developed for the SER project. Unfortunately, SerWeb became incompatible with newer versions of OpenSER. Another important aspect of SerWeb to be considered is its vulnerabilities. There are very few options for web interfaces to OpenSER. One of the tools we have found is OpenSER administrator. This tool is being developed using Ruby on Rails. While it seems to be a very good tool to administer an OpenSER server, it does not permit to provisioning users in the same way that SerWeb did and it lacks multi-domain support. OpenSER administrator can be found at http://sourceforge.net/projects/openseradmin. Since a tool to build an OpenSER portal was not available , we decided to build our own tool named SerMyAdmin using Java. After a slow start, it is now ready and we are using it to build a book. It is licensed according to GPLv2 and developed in Grails (Groovy on rails). It can be downloaded at http://sourceforge.net/projects/sermyadmin. What you are seeing here is the standalone tool. In our roadmap, we intend to integrate SerMyAdmin into the Liferay portal. Using a content management system such as Liferay (www.liferay.com) will make your task of building a portal much easier than it is today. The SerMyAdmin project can be found at sermyadmin.sourceforge.net. The idea is to facilitate the administration of the OpenSER database. SerMyAdmin is licensed under the GPLv2. Lab—Installing SerMyAdmin SerMyAdmin uses the Grails framework, so it needs an application server. You can choose from many application servers, such as IBM WebSphere, JBoss, Jetty, Tomcat, and so on. In this article we will use Apache Tomcat, because it's free and easy to install. Because we use some Java 1.5 features, we'll need Sun's Java JDK, not the free alternative GCJ. Step 1: Create an administrator for SerMyAdmin: mysql –u rootuse openserINSERT INTO 'subscriber' ( 'id' , 'username' , 'domain' , 'password' , 'first_name' , 'last_name' , 'email_address' , 'datetime_created' , 'ha1' , 'ha1b' , 'timezone' , 'rpid' , 'version' , 'password_hash' , 'auth_username' , 'class' , 'domain_id' , 'role_id' )VALUES (NULL , 'admin', 'openser.org', 'senha', 'Admin', 'Admin', 'admin@openser.org', '0000-00-00 00:00:00', '1', '1', '1', '1', '1', NULL , 'admin@openser.org', NULL , '1', '3'); Step 2: The next step we will take is to update our source's list to use the contrib repository and non-free packages. Our /etc/apt/sources.list, should look like below: # /etc/apt/souces.listdeb http://ftp.br.debian.org/debian/ etch main contrib non-freedeb-src http://ftp.br.debian.org/debian/ etch main contrib non-freedeb http://security.debian.org/ etch/updates main contrib non-freedeb-src http://security.debian.org/ etch/updates main contrib non-free/etc/apt/sources.list Notice that we have added only the keywords contrib and non-free after our repository definitions. Step 3: Update the package listing using the following command: openser:~# apt-get update Step 4: Install Sun's Java 1.5, running the command below: openser:~# apt-get install sun-java5-jdk Step 5: Make sure you are using Sun's Java. Please, run the command below to tell Debian that you want to use Sun's Java as your default Java implementation. openser:~# update-java-alternatives -s java-1.5.0-sun Step 6: If everything has gone well so far, you should run the following command and get a similar output. openser:~# java -version java version "1.5.0_14" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_14-b03) Java HotSpot(TM) Client VM (build 1.5.0_14-b03, mixed mode, sharing) Step 7: Install Tomcat. You can obtain Tomcat at: http://tomcat.apache.org/download-60.cgi. To install Tomcat, just run the commands below: openser:/usr/local/etc/openser# cd /usr/localopenser:/usr/local# wget http://mirrors.uol.com.br/pub/apache/tomcat/tomcat-6/v6.0.16/bin/apache-tomcat-6.0.16.tar.gzopenser:/usr/local# tar zxvf apache-tomcat-6.0.16.tar.gzopenser:/usr/local# ln -s apache-tomcat-6.0.16 tomcat6 Step 8: To start Tomcat on your server initialization, please copy the following script to /etc/init.d/tomcat6. #! /bin/bash –e#### BEGIN INIT INFO# Provides: Apache’s Tomcat 6.0# Required-Start: $local_fs $remote_fs $network# Required-Stop: $local_fs $remote_fs $network# Default-Start: 2 3 4 5# Default-Stop: S 0 1 6# Short-Description: Tomcat 6.0 Servlet engine# Description: Apache’s Tomcat Servlet Engine### END INIT INFO## Author: Guilherme Loch Góes <glwgoes@gmail.com>#set -ePATH=/bin:/usr/bin:/sbin:/usr/sbin:CATALINA_HOME=/usr/local/tomcat6CATALINA_BIN=$CATALINA_HOME/bintest -x $DAEMON || exit 0. /lib/lsb/init-functionscase "$1" in start) echo "Starting Tomcat 6" "Tomcat6" $CATALINA_BIN/startup.sh log_end_msg $? ;; stop) echo "Stopping Tomcat6" "Tomcat6" $CATALINA_BIN/shutdown.sh log_end_msg $? ;; force-reload|restart) $0 stop $0 start ;; *) echo "Usage: /etc/init.d/tomcat6 {start|stop|restart}" exit 1 ;;esacexit 0 Step 9: Instruct Debian to run your script on startup; we do this with the command below. openser: chmod 755 /etc/init.d/tomcat6 openser:/etc/init.d# update-rc.d tomcat6 defaults 99 Step 10: To make sure everything is running correctly, reboot the server and try to open in your browser the URL http://localhost:8080; if everything is OK you'll be greeted with Tomcat's start page. Step 11: Install the MySQL driver for Tomcat, so that SerMyAdmin can access your database. This driver can be found at http://dev.mysql.com/downloads/connector/j/5.1.html. You should download the driver and unpack it, then copy the connector to Tomcat's shared library directory, as follows. openser:/usr/src# tar zxf mysql-connector-java-5.1.5.tar.gz openser:/usr/src# cp mysql-connector-java-5.1.5/mysql-connector-java-5.1.5-bin.jar /usr/local/tomcat6/lib Step 12: Declare the data source for SerMyAdmin to connect to OpenSER's database. You can do this in an XML file found at /usr/local/tomcat6/conf/context.xml. The file should look as below: <?xml version="1.0" encoding="UTF-8"?><Context path="/serMyAdmin"> <Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" maxActive="20" maxIdle="10" maxWait="-1" name="jdbc/openser_MySQL" type="javax.sql.DataSource" url="jdbc:mysql://localhost:3306/openser" username="sermyadmin" password="secret"/></Context> In the file above, please change the highlighted parameters according to your scenario. SerMyAdmin can be installed in a different server than the one that holds the database. Do this for better scalability when possible. The default MySQL installation on Debian only accepts requests from localhost, so you should edit the file /etc/mysql/my.cnf, for MySQL to accept requests from external hosts. Step 13: Create a user to be referenced in the file context.xml. This user will have the required access to the database. Please, run the commands below: openser:/var/lib/tomcat5.5/conf# mysql -u root –p Enter password: Welcome to the MySQL monitor. Commands end with ; or g. Your MySQL connection id is 14 Server version: 5.0.32-Debian_7etch5-log Debian etch distribution Type 'help;' or 'h' for help. Type 'c' to clear the buffer. mysql> grant all privileges on openser.* to sermyadmin@'%' identified by 'secret'; Query OK, 0 rows affected (0.00 sec) Step 14: We're almost there. The next step is to deploy the SerMyAdmin WAR file. Please, download and copy the file serMyAdmin.war to Tomcat's webapps directory. Restart it, to activate the changes. openser:/usr/src# cp serMyAdmin-0.4.war /usr/local/tomcat6/webapps/serMyAdmin.war openser:/usr/src# invoke-rc.d tomcat6 restart Don't worry about database modifications; SerMyAdmin will automatically handle that for you. Step 15: Configure Debian's MTA (Message Transfer Agent) to allow SerMyAdmin to send a confirmation email to new users. Run the command below to configure Exim4 (default MTA for Debian). Ask your company's email administrator. openser:/# apt-get install exim4 openser:/# dpkg-reconfigure exim4-config You will be greeted with a dialog-based configuration menu; on this menu it's import to pay attention to two options: General type of mail configuration, which should be set to Internet Site so that we can send and receive mails directly using SMTP, and Domains to relay mail for, which should be set to the domain from which you want the emails from SerMyAdmin to appear to come. Step 16: Customize the file /usr/local/apache-tomcat-6.0.16/webapps/serMyAdmin-0.3/WEB-INF/spring/resource.xml, which contains the parameters that specify which email server is used to send mails and from whom these emails should appear to come from. The following is an example of this file: <?xml version="1.0" encoding="UTF-8"?><beans xsi_schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host"><value>localhost</value></property> </bean> <!-- You can set default email bean properties here, eg: from/to/subject --> <bean id="mailMessage" class="org.springframework.mail.SimpleMailMessage"> <property name="from"><value>admin@sermyadmin.org</value></property> </bean></beans> The first parameter to change is the server that we will use to send emails. The second is the parameter specifying from whom those emails will appear to come. Restart Tomcat again and we're ready to go. When you point your browser to http://<server address>:8080/serMyAdmin you should be greeted with the login page, the same as we have shown at the start on this article.
Read more
  • 0
  • 0
  • 1851

article-image-overview-cherrypy-web-application-server-part2
Packt
27 Oct 2009
5 min read
Save for later

Overview of CherryPy - A Web Application Server (Part2)

Packt
27 Oct 2009
5 min read
Library CherryPy comes with a set of modules covering common tasks when building a web application such as session management, static resource service, encoding handling, or basic caching. The Autoreload Feature CherryPy is a long-running Python process, meaning that if we modify a Python module of the application, it will not be propagated in the existing process. Since stopping and restarting the server manually can be a tedious task, the CherryPy team has included an autoreload module that restarts the process as soon as it detects a modification to a Python module imported by the application. This feature is handled via configuration settings. If you need the autoreload module to be enabled while in production you will set it up as below. Note the engine.autoreload_frequency option that sets the number of seconds the autoreloader engine has to wait before checking for new changes. It defaults to one second if not present. [global]server.environment = "production"engine.autoreload_on = Trueengine.autoreload_frequency = 5 Autoreload is not properly a module but we mention it here as it is a common feature offered by the library. The Caching Module Caching is an important side of any web application as it reduces the load and stress of the different servers in action—HTTP, application, and database servers. In spite of being highly correlated to the application itself, generic caching tools such as the ones provided by this module can help in achieving decent improvements in your application's performance. The CherryPy caching module works at the HTTP server level in the sense that it will cache the generated output to be sent to the user agent and will retrieve a cached resource based on a predefined key, which defaults to the complete URL leading to that resource. The cache is held in the server memory and is therefore lost when stopping it. Note that you can also pass your own caching class to handle the underlying process differently while keeping the same high-level interface. The Coverage Module When building an application it is often beneficial to understand the path taken by the application based on the input it processes. This helps to determine potential bottlenecks and also see if the application runs as expected. The coverage module provided by CherryPy does this and provides a friendly browseable output showing the lines of code executed during the run. The module is one of the few that rely on a third-party package to run. The Encoding/Decoding Module Publishing over the Web means dealing with the multitude of existing character encoding. To one extreme you may only publish your own content using US-ASCII without asking for readers' feedback and to the other extreme you may release an application such as bulletin board that will handle any kind of charset. To help in this task CherryPy provides an encoding/decoding module that filters the input and output content based on server or user-agent settings. The HTTP Module This module offers a set of classes and functions to handle HTTP headers and entities. For example, to parse the HTTP request line and query string: s = 'GET /note/1 HTTP/1.1' # no query stringr = http.parse_request_line(s) # r is now ('GET', '/note/1', '','HTTP/1.1')s = 'GET /note?id=1 HTTP/1.1' # query string is id=1r = http.parse_request_line(s) # r is now ('GET', '/note', 'id=1','HTTP/1.1')http.parseQueryString(r[2]) # returns {'id': '1'}Provide a clean interface to HTTP headers:For example, say you have the following Accept header value:accept_value = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"values = http.header_elements('accept', accept_value)print values[0].value, values[0].qvalue # will print text/html 1.0 The Httpauth Module This module provides an implementation of the basic and digest authentication algorithm as defined in RFC 2617. The Profiler Module This module features an interface to conduct a performance check of the application. The Sessions Module The Web is built on top of a stateless protocol, HTTP, which means that requests are independent of each other. In spite of that, a user can navigate an e-commerce website with the impression that the application more or less follows the way he or she would call the store to pass an order. The session mechanism was therefore brought to the Web to allow servers to keep track of users' information. CherryPy's session module offers a straightforward interface to the application developer to store, retrieve, amend, and delete chunks of data from a session object. CherryPy comes natively with three different back-end storages for session objects: Back-end type Advantages Drawbacks RAM Efficient Accepts any type of objects No configuration needed Information lost when server is shutdown Memory consumption can grow fast File system Persistence of the information Simple setup File system locking can be inefficient Only serializable (via the pickle module) objects can be stored Relational database (PostgreSQL built-in support) Persistence of the information Robust Scalable Can be load balanced Only serializable objects can be stored Setup less straightforward
Read more
  • 0
  • 0
  • 2853

article-image-aspnet-35-cms-adding-security-and-membership-part-1
Packt
27 Oct 2009
10 min read
Save for later

ASP.NET 3.5 CMS: Adding Security and Membership (Part 1)

Packt
27 Oct 2009
10 min read
Security is a concern in any web application, but the security this article deals with is that of user accounts, membership, and roles. We'll be using the ASP.NET membership and roles functions to allow certain users such as administrators to perform specific tasks. These tasks may include managing the application, while other users such as content editors, may be restricted to the specific tasks we want them to manage such as adding or changing content. User account management can be handled either by the application (in our case, our Content Management System) or by Windows itself, using standard Windows authentication functions, as well as file and folder permissions. The advantage of an application-based user authentication system is primarily in cost. To use Windows authentication, we need to purchase Client Access Licenses (CALs) for each user that will access our application. This is practical in an intranet, where users would have these licenses to perform other functions in the network. However, for an Internet application, with potentially thousands of users, licensing could be extremely expensive. The drawback to an application-based system is that there is a lot more work to do in designing and using it. The Windows authentication process has been around for years, continually improved by Microsoft with each Windows release. It scales extremely well, and with Active Directory, can be extended to manage just about anything you can think of. ASP.NET membership Fortunately, Microsoft has provided relief for application-based authentication drawbacks in the 2.0 version of the ASP.NET framework, with the ASP.NET membership functions, and in our case, the SqlMembershipProvider. The membership API makes it simple for us to use forms authentication in our application, retrieving authentication and membership information from a membership provider. The membership provider abstracts the membership details from the membership storage source. Microsoft provides two providers—the ActiveDirectoryMembershipProvider that uses Active Directory and the SqlMembershipProvider that uses an SQL server database for the user data store. By default, ASP.NET authentication uses cookies—small text files stored on the user's system—to maintain authentication status throughout the application. These cookies normally have an expiration time and date, which requires users to log in again after the cookie has expired. It is possible to use cookies to allow the client system to authenticate the application without a user login, commonly seen as a "Remember Me" checkbox in many web site login pages. There is naturally a downside to cookies in that a client system may not accept cookies. ASP.NET can encode the authentication information into the URL to bypass this restriction on cookies. Although in the case of our application, we will stick with the cookie method. Forms authentication secures only ASP.NET pages. Unless you are using IIS7, and the integrated pipeline, where ASP.NET processes all file requests, the ASP.NET DLL won't be called for non-ASP.NET pages. This means that you cannot easily secure HTML pages, PDF files, or anything other than ASP.NET through forms authentication. Configuring and using forms authentication Let's start learning ASP.NET forms authentication by walking through a brand new application. We'll then add it to our Content Management System application. Forms authentication is actually quite simple, both in concept and execution, and a simple application can explain it better than adopting our current CMS application. Of course, we eventually need to integrate authentication into our CMS application, but this is also easier once you understand the principles and techniques we'll be using. Creating a new application Start by opening Visual Web Developer 2008 Express and creating a new web site by clicking on File | New Web Site. Use the ASP.NET Website template, choose File System, and name the folder FormsDemo. When the site is created, you are presented with a Default.aspx page created with generic code. We will use this as our home page for the new site, although we need to modify it for our needs. Creating the home page Visual Web Developer 2008 Express creates a generic Default.aspx file whenever you create a new site. Unfortunately, the generic file is not what we want and will need modification. The first thing we want to do is make sure our site uses a Master Page, just as our Content Management System application will. To do this, we could delete the page, create our Master Page, and then add a new Default.aspx page that uses our Master Page. In the case of a brand new site, it's pretty easy, but what if you have developed an extensive site that you want to convert to Master Pages? You would want to add a Master Page to an existing site, so let's go ahead and do that. Create the Master Page To create a Master Page, leave the Default.aspx file open and press Ctrl+Shift+A to add a new item to the solution. Choose the Master Page template and leave the name as MasterPage.Master. Place the code in a separate file and click Add to create the Master Page. You will notice that this creates the same generic code as in the previous chapter. Unfortunately, our Default.aspx file is not a content page and won't use the MasterPage.Master we just created, unless we tell it to. To tell our Default.aspx page to use the MasterPage.Master, we need to add the MasterPageFile declaration, in the @ Page declaration, at the top of the file. Add the following code between the Language and AutoEventWireup declarations: MasterPageFile="~/MasterPage.master" This adds the Master Page to our Default.aspx page. However, content pages include only those Content controls that match the Master Page, not the full page code as our Default.aspx page currently does. To fix this, replace the remaining code outside the @ Page declaration with the following two Content controls: <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server"></asp:Content><asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> <h1>This is where the content goes.</h1></asp:Content> We've left the Content1 control empty for the moment, and we've added a simple text statement to the Content2 control so that it can be tested. If you view the Default.aspx page in a browser, you should see the relatively uninteresting web page below: Enabling forms authentication Okay, we have a boring home page for our new site. Let's leave it for a moment and enable forms authentication for the site, so we can restrict who can access our home page. The process of enabling forms authentication is simply adding a few lines to our web.config file. Or in the case of the generic web.config file, which we created while creating our new site, we simply need to alter a single line. Open the web.config file in the new site and look for the line that says: <authentication mode="Windows" /> Edit it to read: <authentication mode="Forms" /> Save the web.config file and you have now enabled forms authentication for this site. The default authentication mode for ASP.NET applications is Windows, which is fine if you're working in an intranet environment where every user probably has a Windows login for use in the corporate network anyway. Using Windows authentication, Windows itself handles all the security and authentication, and you can use the myriad of Windows utilities and functions such as Active Directory, to manage your users. On the other hand, with forms authentication, ASP.NET is expected to handle all the details of authentication and security. While ASP.NET 2.0 and later have sophisticated membership and profile capabilities, there is no ASP.NET mechanism for protecting files and folders from direct access, outside of the application. You will still need to secure the physical server and operating system from outside of your application. Creating the membership database To use forms authentication and the SqlMembershipProvider, we need to create a database to authenticate against. This database will hold our user information, as well as membership information, so we can both authenticate the user and provide access based on membership in specific roles. For our demonstration, we will create a new database for this function. We'll create a database with SQL Server ManagementExpress, so open it and right-click Databases in the Object Explorer pane. Choose New Database and name it FormsDemo. Change the location of the database path to the App_Data folder of your FormsDemo web application—the default is C:InetpubFormsDemoApp_Data as shown below. Click OK and the new database will be created. If you look at this database, you will see that it is empty. We haven't added any tables to it, and we haven't set up any fields in those non-existent tables. The database is pretty much useless at this stage. We need to create the database layout, or schema, to hold all the authentication and membership details. Fortunately, Microsoft provides a simple utility to accomplish this task for the 2.0 version of the ASP.NET framework – aspnet_regsql.exe. We'll use this too, in order to create the schema for us, and make our database ready for authentication and membership in our application. To use aspnet_regsql.exe, we need to provide the SQL Server name and login information. This is the same information as shown in the login dialog when we open the database in SQL Server Management Studio Express, as shown below: Note the server name, it will usually be {SystemName}/SQLEXPRESS, but it may be different depending on how you set it up. We use SQL Server Authentication with the sa account and a password of SimpleCMS when we set up SQL Server Express 2005, and that's what we'll use when we run the aspnet_regsql.exe tool. To run aspnet_regsql.exe, you may browse to it in Windows Explorer, or enter the path into the Run dialog when you click on Start and then Run. The default path is C:WINDOWSMicrosoft.NETFrameworkv2.0.50727aspnet_regsql.exe. The utility may be run with command-line arguments, useful when scripting the tool or using it in a batch file, but simply running it with no parameters brings it up in a GUI mode. When the ASP.NET SQL Server Setup Wizard launches, click Next. Make sure that the Configure SQL Server for application services is selected and click on Next. The ASP.NET SQL Server Setup Wizard will ask for the server, authentication, and database. You should enter these according to the information from above. Click Next to confirm the settings. Click Next again to configure the database with the ASP.NET users and membership schema. Continue and exit the wizard, and the database is ready for us to use for authentication. If you were to open the FormsDemo database in SQL Server Management Studio Express, you would find that new tables, views, and stored procedures have been added to the database during this configuration process.
Read more
  • 0
  • 0
  • 2832

article-image-real-content-php5-cms-part-1
Packt
27 Oct 2009
14 min read
Save for later

Real Content in PHP5 CMS: Part 1

Packt
27 Oct 2009
14 min read
The problem There are some common features in providing website content, but also many differences. Applications easily become complex as they tackle real world problems, and there has been much real innovation in web systems. So the areas to look at in this article are: Major areas for content development A review of minor yet important areas How a simple text manager is built An outline of a complex content delivery extension Discussion and considerations Now, we will work through the major areas of website content, devoting a section to each one. A round up of some less important aspects of content completes the discussion, leaving us ready to move on to details of implementation. Articles, blogs, magazines, and FAQ The most basic requirement is for text and pictures, and the simplest scheme needs little more than the standard database and a WYSIWYG editor. An extension that works at this level is illustrated later in the article. It is pretty much essential to have an ability to create items of this kind in an unpublished state so that they can be revised until ready for use. The state is then changed to published. Almost immediately, a further requirement arises to specify a range of publication dates, so that material aimed at a specific event can be automatically published at the appropriate time. Likewise, it is desirable to have an automatic mechanism for removing information that is no longer current, for example because it refers to a coming event in terms that will be irrelevant once the event has passed. A website that carries plainly obsolete articles is unlikely to be popular! There are many ways to organize textual material. One is to place it into some kind of tree structure, rather akin to the classification schemes used in libraries. Ideally, such a scheme has no particular constraints on the depth of the tree structure. A concern with this approach is that it can quickly lead to a conflict between two alternative uses—classification according to subject and classification according to reader permissions. An option that can be used in conjunction with a tree structure is to use some form of tagging. This introduces much greater flexibility in some respects, as it is easy to apply multiple tags to a single item of content, which can therefore be classified in a wide variety of ways, and can appear under multiple headings. A blog is an example of a system that might work best with a combination of a classification tree and a tagging scheme. Where there are several people creating blogs, the different authors fit well with a tree structure, since there is no question of an item belonging to more than one author. On the other hand, items are often tagged according to their subject matter, and several tags may be applicable to an individual article. If authors create more than one blog and there are questions about which visitors are able to see which blog, then careful thought needs to be given as to whether the split of blogs is best handled by the classification tree or by tagging. Using a tree achieves rigid separation, and is easily amenable to imposing access controls. But if the same item appears in more than one blog, then tagging works better as the item is ideally stored only once but has multiple tags. Blogs also frequently provide for comments, discussed in the next section. A magazine is typically a collection of articles. For a simple case, it might be adequate for the articles of the magazine to be equated to website pages, but a more sophisticated magazine would want to avoid restrictions of that kind. The basic unit of content would still need to be an individual article, but website pages then require some kind of template to build a page from multiple items. One popular application for quite simple content is the compilation of frequently asked questions (FAQ's). Advanced implementations might be described more grandly as knowledge bases. Again, both a classification tree and tagging can be relevant, but a useful FAQ (and especially one that wants to be a knowledge base) also needs effective search facilities so that information can be easily found. In all of these cases, added complexity arises if facilities like versioning are needed. Another similar issue is the need for workflow and differing roles, such as authors and editors. Mention of roles suggests a RBAC mechanism. It seems unlikely that one single model will ever meet every requirement in areas such as versioning and workflow. Version control can become extremely complex, and usually requires the allocation of roles that involve access rights and functional capabilities. Workflow is much the same. In both cases, though, simple and rigid schemes are liable to create problems. For example, the same person is quite likely to be an author in some situations, and an editor or publisher in others. A flexible and an efficient RBAC system is a pre-requisite for handling these problems, but as discussed earlier, the technical provision of RBAC is only a start. Applying it to particular systems and creating an appropriate user interface is a considerable challenge. Comments and reviews One of the successful innovations brought about by widespread use of the Web has been feedback through comments and reviews. Amazon is only one of many sites that now include reviews by customers of the products on sale. It could be said that this is a form of social networking, as the more sophisticated sites maintain profiles of reviewers and encourage them to achieve their own identity. Regular readers in particular areas of interest can get to know reviewers and form an opinion on the reliability of their views. There are two main problems with implementing comments and reviews. One is the question of how to generalize the facility, so as to avoid implementing it repeatedly in different applications. The other is how to deal with the ever present threat of spam. From the point of view of a developer, handling comments raises much the same issues regardless of what may be the subject of the comments. So blogs, selections of products, image galleries, and so on are all capable of having comments added to their items using similar mechanisms. This suggests a structure something like the scheme where the coarse grained structure is the component, but its display is achieved through the use of a template and a number of modules. Comments can thus be generated by a module that knows relatively little about the application, only enough to keep its comments separate from those for other applications and to relate a set of comments to a particular item, whether it is a blog item, product, gallery image, or whatever. That deals with the display of existing comments, which still leaves a requirement for a general interface that allows new comments to be added. The comment facility can easily enough handle the acceptance of a new comment, although it may need help if the page that accepts comments is to also show the object to which the comment applies. The comment facility also needs to know where to hand control once a new comment has been completed. Some moderately tricky detailed design is involved in providing an implementation of the full scheme. The other big problem with any facility that permits visitors to a site to enter information for display is that it attracts spammers. Usually, they arrive not in person but in the form of automated bots that can become very sophisticated. There are bots that know how to obtain an account, and log in to a range of systems. There are even bots that can handle CAPTCHAs (those messed up images out of which you are supposed to decipher letters or numbers). Some of the bots can handle CAPTCHAs better than some humans, which makes for accessibility problems. Fortunately, much link spamming is for the purpose of promoting websites, and so the spammer has to give away some information in the form of the link to the site being promoted. A reasonably effective defense against this kind of spamming is a collaborative scheme for blacklisting sites. Even that is not totally effective, as spammers find ways to create new sites quickly and cheaply, so that the threat is constantly changing. As with most forms of attack, there is unlikely to be any conclusion to this battle. Forums Forums are a very popular Web feature, providing a structured means for public or private discussion. Developing a forum is a major undertaking, and most people will prefer to choose from existing software products. Forum software usually provides for visitors to contribute messages, either starting a new topic or replying to an existing one. There is often a hierarchical structure to the messages so that a number of different areas of interest can be covered in a convenient way. Advanced systems include sophisticated user management, including support for a variety of different groups, which provides a means to decide who has access to which topics. Unwanted messages are a constant threat, and most active forums need moderators to weed them out. Development of a new forum will clearly need a number of the framework features discussed earlier. Robust user control is essential, and if different users are granted different access rights, a good system of RBAC is a requirement. A forum is highly amenable to the use of cache, since pages are likely to be constructed out of a number of database records, but the records are updated relatively infrequently. To be responsive, the cache needs to have a degree of intelligence so that pages with new contributions are refreshed quickly. Mail services are likely to be employed so that subscribers can receive notification of new contributions to topics in which they have registered an interest. Another approach is to seek a degree of integration between off the shelf forum software and the CMS. The most popular area for integration is user login. Obviously it is necessary to obtain some information about the way in which the forum software is implemented. Provided that can be found, then it is a relatively simple matter to integrate with a CMS that has been built with plentiful plug in triggers around the area of user authentication. From the point of view of visual integration, the amount of screen space needed by a forum is such that it is often difficult to build it within the framework of a typical CMS. Often a better approach is to build a custom theme for the forum that includes links back to the main site, so as to avoid completely losing continuity of navigation. Galleries, repositories, and streaming Although they have come from different requirements, galleries, and file repositories have a lot in common. Both start out simple and rapidly become complex. The general idea of a gallery is to build a collection of images, typically organized into categories and accessible via small versions of the images (thumbnails). File repositories have long been popular since the days of bulletin boards, where collections of files (often programs) were made available for download. Ideally the organization into categories (or folders or containers) is flexible with no particular limit on the depth to which subcategories can go. Some basic requirements relate to security. It is obviously essential to avoid hosting files that could contain malicious PHP code. This includes avoiding uploads of image files that contain PHP code embedded within actual image data. Simple checks can be fooled by this technique, but a block on the .php extension prevents the code being interpreted. Another potentially major security issue is bandwidth theft. If files or images are too easily accessed, then other sites may choose to use them without acknowledgment, transferring the bandwidth costs to the site hosting the material. As applications broaden, access control becomes an issue. Files are to be made available only to a restricted group, and uploads may be restricted more tightly again. There may be administrator oversight, with uploads needing approval. Once again, we are seeing a demand for an effective access control system, preferably role-based. In fact demands on systems of this kind can easily become very sophisticated, such as allowing users to have personal upload areas over which they have complete control to determine who is able to gain access. An RBAC system that is technically capable of handling this can be built relatively easily, although creating a good user interface is a challenge. Whether the system is a gallery or file repository, the use of thumbnail images is increasingly prevalent. File uploads may, therefore, be accompanied by one or more image files that are used to enhance the display of the files available. Information about the system is likely to be needed, such as which are the most recent additions to the collection, which items are most popular, who has accessed what, and who has uploaded what. Information of this kind can also contribute to security by providing an audit trail of what has been happening to the system. Streaming of files is a demand now often placed on a file repository, as the files can be audio or video files made available for immediate access. Streaming is simply a mode of file processing whereby the information is delivered to the user at a speed adequate for consumption in real time. Clearly video tends to place greater demands on the system than audio. The problems are both hardware and software related, although with steadily improving technology it is increasingly feasible to overcome both. E-commerce and payments Everyone is aware of the huge growth of commercial transactions on the Web. The kind of transaction involved can vary widely across simple fixed price retail sales, auctions of various kinds, and reverse auctions for procurement. For retail transactions immediate settlement is usually required, whereas larger scale business to business transactions are usually handled through relatively traditional invoicing methods. Even those are tending to be altered towards paperless billing and payment schemes that cut transaction costs to a minimum. Systems for e-commerce vary enormously in their sophistication from simple requests for payment using a PayPal button to highly sophisticated Web operations such as Amazon and eBay. Open source PHP software exists to cover a significant part of this spectrum, some of it in the form of extensions to CMS frameworks. PayPal has achieved a very high profile, especially with smaller operators, by offering easy access for merchants combined with technology that is relatively simple to implement. This includes the ability to complete a transaction with online confirmation in a way that is suitable for the sale of electronically deliverable goods such as software. Clearly, robust authentication of users is essential for e-commerce. For all but the simplest transactions, some kind of shopping cart is highly desirable. These requirements imply a need for good session handling, preferably taking effect as soon as a visitor arrives at a site. Nearly every shopping site will allow a visitor to accumulate items in a shopping cart prior to any kind of login. There is a plethora of payment systems, some of them suitable mainly for large volume uses, but others that can be applied on a small scale. A particular CMS framework might adopt some standard payment mechanisms that are then integral to the CMS and can be used whenever needed. Security is obviously paramount, as loss of data is both financially damaging and extremely bad for the site's reputation. E-commerce sites also often use a number of the features described in other sections here. A popular addition is the ability for customers to review the items they have purchased. This kind of facility may lead to further requirements to distinguish categories of users so as to give incentives to people who regularly write reviews.
Read more
  • 0
  • 0
  • 1689
article-image-real-content-php5-cms-part-2
Packt
27 Oct 2009
8 min read
Save for later

Real Content in PHP5 CMS: Part 2

Packt
27 Oct 2009
8 min read
Framework solution To explore implementation details, we will look at an example that is simple enough to be shown in some detail. It is an application for handling pages composed largely of text and images. After studying the example, we will consider how the application could be made more advanced. A simple text application Here, we'll look at a component that can be used on its own but is also intended as a starting point for more sophisticated uses. Its essence is that it handles a piece of text, created using the site WYSIWYG editor by the administrator. The text can be displayed as the main portion of a Web page. Ancillary information is held about the text. Any particular text can be the target of a menu entry, so the component can be used for simple pages. The WYSIWYG editor provides for moderately complex text layout and the inclusion of images. We shall see that writing a text handling extension is made very much simpler by the various elements of the CMS framework. The database table for simple text After the ID number that is used as the main key we have the primary constituents of a piece of text. They are the headline, the subheading, and the body of the article. Each of these will simply reflect whatever text is put in them by the author, who in this simple implementation must also be an administrator. Next we have a couple of time stamps that can be automatically maintained by the software. Rather obviously, the created time stamp is set when the row is created, and the modified time stamp is set every time the row is updated. We then have fields that control the publication of the text. First, there is a simple indicator, which is set to zero if the text is not published and is set to one if it is published. When set to unpublished, the indicator overrides the start and end dates, if they are present. If a non-zero start date is set, then the text will not be published before that date. Likewise, if a non-zero finish date is set, the article will cease to be published after that date. Publishing dates are very useful to control when text will appear as it is often helpful to time the start of publication, and it creates a bad impression if obsolete text is not removed. Then we have data that describes who has worked on the text. The original creator is recorded as a user ID, and the last modifier is likewise recorded as a user ID. These fields are intended for tracking what is happening to the text rather than for display. On the other hand, the byline is entirely for display. Version is a character field that has no defined structure in this simple component, but could be elaborated in many different ways. Storage for metadata is provided as keys and description. This information is not for display on the browser page, but is used to generate meta information in the header of a page containing the text. Tags containing metadata can influence search engines used for indexing of pages, although description is much more influential than keywords, which are believed to be largely disregarded. Finally, a hit counter is automatically maintained by the system, being set initially to zero and then updated every time the text is shown to a site visitor. A text data object When a text item is loaded into memory from the database, a class provides for the definition of the object will be created. For the simple text application, the class is: class textItem extends aliroDatabaseRow { protected $DBclass = 'aliroDatabase'; protected $tableName = '#__simple_text'; protected $rowKey = 'id'; public function store ($updateNulls=false) { $userid = aliroUser::getInstance()->id; if ($this->id) { $this->modified = date('Y-m-d H:i:s'); $this->modify_id = $userid; } else { $ this->created = date('Y-m-d H:i:s'); $this->author_id = userid; } parent::store($updateNulls); } } Much of the hard work is done in the parent class, aliroDatabaseRow. Because the database framework derives information from the database itself, there is no need to specify the fields that are in the table, which makes it easier to cope with future changes. The minimum that has to be done is to specify the name of the singleton database class, the name of the table (using a symbol in place of the actual prefix), and to define the name of the primary key field. In this case, the store method is also extended. This provides an easy way to maintain the time stamps on the text. The current user is found through the aliroUser singleton class. We know whether a text row is new from whether it already has a value for id. The correct date and user field can then be updated. Finally, the standard store method in the parent class is invoked. Administering text items—controller The administrator logic for handling simple text follows the usual pattern of first providing a list of items, paged if necessary, then allowing more detailed access to individual items, including the ability to edit. Logic for overall control is provided by the aliroComponentAdminManager class, and the aliroComponentAdminControllers class. In fact, we could nominate in the packaging XML aliroComponentAdminManager as the adminclass for our component, since the dedicated textAdmin class does nothing: class textAdmin extends aliroComponentAdminManager { // This could be omitted - included here in case extra code needs to be added public function __construct ($component, $system, $version) { parent::__construct ($component, $system, $version); } // Likewise, this could be omitted unless extra code is needed public function activate () { parent::activate(); } } Why might we want to write a dedicated extension to aliroComponentAdminManager? Well, this is the common entry point for the administrator side of our component, so if we wanted any processing to exist that could affect every use of the component, this is the place to put it. The two possible locations are the constructor and the activation method. The constructor receives information from the CMS environment in the form of a component object (describing this component), the name of the system that is calling us, and its version. It is invoked as soon as the correct component has been determined. The standard processing in the aliroComponentAdminManager constructor includes creating the controller class, and acquiring some common variables from $_REQUEST. Once setup is completed, the activation method is invoked without any parameters. The activate method of the aliroComponentAdminManager class strips any magic quotes, and decides what method to call. Of course, the framework allows us to construct a component completely differently if we choose. The only constraint is that we must write a class whose name is given in the packaging XML, and provide it with an activate method. But usually it is a lot easier to follow the standard construction, and the bare bones of a new component can be built and downloaded online from http://developer.aliro.org. Nothing specific has been done yet, and we have to move into the controller code before we can find anything to do with handling text objects. The controller is subclassed from aliroComponentAdminControllers and starts off as shown: class textAdminText extends aliroComponentAdminControllers { private static $instance = null; // If no code is needed in the constructor, it can be omitted, relying on the parent class protected function __construct ($manager) { parent::__construct ($manager); } public static function getInstance ($manager) { return is_object(self::$instance) ? self::$instance : (self::$instance = new self ($manager)); } public function getRequestData () { // Get information from $_POST or $_GET or $_REQUEST // This method will be called before the toolbar method } // If this method is provided, it should return true if permission test is satisfied, false otherwise public function checkPermission () { $authoriser = aliroAuthoriser::getInstance(); if ($test = $authoriser->checkUserPermission('manage', 'aSimpleText', '*')) { if (!$this->idparm) return true; if ($authoriser->checkUserPermission('edit', 'aSimpleText', $this->idparm)) return true; } return false; } Here, the constructor is not needed; it is shown only to indicate the possibility of having code at the point the controller object is created. The constructor receives the manager object as a parameter, in this case an instance of textAdmin, a subclass of aliroComponentAdminManager. The controller is a singleton class, and here a form of the getInstance method is shown that can be used completely unchanged from component to component. Then we have two methods that are standard. Neither has to be provided, and in this case, the getRequestData method is not needed since it does nothing. Its purpose is to run early on (it is called before the toolbar processing and well before the processing specific to the current request) to acquire information from $_REQUEST or $_GET or $_PUT (or possibly other super-globals). They can be saved as object properties so as to be available for toolbar construction or other processing. The checkPermission method provides the component with a way to easily control who is able to access its facilities. If the method returns true then the user will be allowed to continue, but if it returns false, they will be refused access. In this example, there is always a check that the user is permitted to manage objects of the type aSimpleText and if a specific one is identified by its ID, then there is a further check that the user is permitted to edit that particular text item.
Read more
  • 0
  • 0
  • 1832

article-image-overview-cherrypy-web-application-server-part1
Packt
27 Oct 2009
6 min read
Save for later

Overview of CherryPy - A Web Application Server (Part1)

Packt
27 Oct 2009
6 min read
Vocabulary In order to avoid misunderstandings, we need to define a few key words that will be used. Keyword Definition Web server A web server is the interface dealing with the HTTP protocol. Its goal is to transform incoming HTTP requests into entities that are then passed to the application server and also transform information from the application server back into HTTP responses. Application An application is a piece of software that takes a unit of information, applies business logic to it, and returns a processed unit of information. Application server An application server is the component hosting one or more applications. Web application server A web application server is simply the aggregation of a web server and an application server into a single component. CherryPy is a web application server. Basic Example To illustrate the CherryPy library we will go through a very basic web application allowing a user to leave a note on the main page through an HTML form. The notes will be stacked and be rendered in a reverse order of their creation date. We will use a session object to store the name of the author of the note. Each note will have a URI attached to itself, of the form /note/id. Create a blank file named note.py and copy the following source code. #!/usr/bin/python# -*- coding: utf-8 -*# Python standard library importsimport os.pathimport time################################################################The unique module to be imported to use cherrypy###############################################################import cherrypy# CherryPy needs an absolute path when dealing with static data_curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))################################################################ We will keep our notes into a global list# Please not that it is hazardous to use a simple list here# since we will run the application in a multi-threaded environment# which will not protect the access to this list# In a more realistic application we would need either to use a# thread safe object or to manually protect from concurrent access# to this list###############################################################_notes = []################################################################ A few HTML templates###############################################################_header = """<html><head><title>Random notes</<title><link rel="stylesheet" type="text/css" href="/style.css"></link></head><body><div class="container">"""_footer = """</div></body></html>"""_note_form = """<div class="form"><form method="post" action="post" class="form"><input type="text" value="Your note here..." name="text"size="60"></input><input type="submit" value="Add"></input></form></div>"""_author_form = """<div class="form"><form method="post" action="set"><input type="text" name="name"></input><input type="submit" value="Switch"></input></form></div>"""_note_view = """<br /><div>%s<div class="info">%s - %s <a href="/note/%d">(%d)</a></div></div>"""################################################################ Our only domain object (sometimes referred as to a Model)###############################################################class Note(object):def __init__(self, author, note):self.id = Noneself.author = authorself.note = noteself.timestamp = time.gmtime(time.time())def __str__(self):return self.note################################################################ The main entry point of the Note application###############################################################class NoteApp:"""The base application which will be hosted by CherryPy"""# Here we tell CherryPy we will enable the session# from this level of the tree of published objects# as well as its sub-levels_cp_config = { 'tools.sessions.on': True }def _render_note(self, note):"""Helper to render a note into HTML"""return _note_view % (note, note.author,time.strftime("%a, %d %b %Y %H:%M:%S",note.timestamp),note.id, note.id)@cherrypy.exposedef index(self):# Retrieve the author stored in the current session# None if not definedauthor = cherrypy.session.get('author', None)page = [_header]if author:page.append("""<div><span>Hello %s, please leave us a note.<a href="author">Switch identity</a>.</span></div>"""%(author,))page.append(_note_form)else:page.append("""<div><a href="author">Set youridentity</a></span></div>""")notes = _notes[:]notes.reverse()for note in notes:page.append(self._render_note(note))page.append(_footer)# Returns to the CherryPy server the page to renderreturn page@cherrypy.exposedef note(self, id):# Retrieve the note attached to the given idtry:note = _notes[int(id)]except:# If the ID was not valid, let's tell the# client we did not find itraise cherrypy.NotFoundreturn [_header, self._render_note(note), _footer]@cherrypy.exposedef post(self, text):author = cherrypy.session.get('author', None)# Here if the author was not in the session# we redirect the client to the author formif not author:raise cherrypy.HTTPRedirect('/author')note = Note(author, text)_notes.append(note)note.id = _notes.index(note)raise cherrypy.HTTPRedirect('/')class Author(object):@cherrypy.exposedef index(self):return [_header, _author_form, _footer]@cherrypy.exposedef set(self, name):cherrypy.session['author'] = namereturn [_header, """Hi %s. You can now leave <a href="/" title="Home">notes</a>.""" % (name,), _footer]if __name__ == '__main__':# Define the global configuration settings of CherryPyglobal_conf = {'global': { 'engine.autoreload.on': False,'server.socket_host': 'localhost','server.socket_port': 8080,}}application_conf = {'/style.css': {'tools.staticfile.on': True,'tools.staticfile.filename': os.path.join(_curdir,'style.css'),}}# Update the global CherryPy configurationcherrypy.config.update(global_conf)# Create an instance of the applicationnote_app = NoteApp()# attach an instance of the Author class to the main applicationnote_app.author = Author()# mount the application on the '/' base pathcherrypy.tree.mount(note_app, '/', config = application_conf)# Start the CherryPy HTTP servercherrypy.server.quickstart()# Start the CherryPy enginecherrypy.engine.start() Following is the CSS which should be saved in a file named style.css and stored in the same directory as note.py. html, body {background-color: #DEDEDE;padding: 0px;marging: 0px;height: 100%;}.container {border-color: #A1A1A1;border-style: solid;border-width: 1px;background-color: #FFF;margin: 10px 150px 10px 150px;height: 100%;}a:link {text-decoration: none;color: #A1A1A1;}a:visited {text-decoration: none;color: #A1A1A1;}a:hover {text-decoration: underline;}input {border: 1px solid #A1A1A1;}.form {margin: 5px 5px 5px 5px;}.info {font-size: 70%;color: #A1A1A1;} In the rest of this article we will refer to the application to explain CherryPy's design.
Read more
  • 0
  • 0
  • 3751

article-image-real-content-php5-cms-part-3
Packt
27 Oct 2009
8 min read
Save for later

Real Content in PHP5 CMS: Part 3

Packt
27 Oct 2009
8 min read
Administering text items—viewer Generating the XHTML is handled in a separate class, thus implementing the principles of the MVC pattern. The viewer class constructor establishes strings for translation in a way that will allow them to be picked up by gettext, as well as invoking the constructor in the parent class basicAdminHTML, which will provide useful methods and also transfer information such as the page navigation object from the controller object passed as a parameter: class listTextHTML extends basicAdminHTML { public function __construct ($controller) { parent::__construct($controller); $lang_strings = array(T_('Simple Text'),T_('Title'), T_('Byline'),T_('Version'), T_('Publishing'),T_('Published'), T_('Start date'),T_('End date'), T_('Article text'),T_('Metadata'), T_('Keys'),T_('Description'), T_('Hits'),T_('ID')); $this->translations = array_combine( $lang_strings, $lang_strings); } The actual display of a list of text items is then quite simple, involving the creation of a heading first, followed by a loop through the text items, and then some final XHTML including hidden fields that allow for effective navigation. Note that the parent class will have set up $this->optionurl and $this->optionline to help in the construction of links within the component and a hidden variable to identify the component respectively. public function view ($rows) { $mainhtml = $this->listview($rows); echo <<<ALL_HTML $mainhtml <div> <input type="hidden" name="task" value="" /> $this->optionline <input type="hidden" name="boxchecked" value="0" /> <input type="hidden" name="hidemainmenu" value="0" /> </div>ALL_HTML; } The view method does very little, relying on the listview method for most of the work, and only adding hidden fields needed to ensure that navigation and the toolbar will work correctly. Note that the parent class helps us by setting $this->optionline with a hidden input field for the critical option variable needed to ensure the correct component is invoked when the form is submitted. Actual XHTML form tags are created by the CMS framework so that every administrator page is a form. The reason for splitting the page creation in this way will become apparent later, when we look at menu creation. So, moving on to the listview method, we find quite a lot of simple code, which is mainly just a definition of the page in XHTML. The second and third parameters will be set differently from their default values when we come to menu creation. public function listview ($rows, $showlinks=true, $subhead='') { $rowcount = count($rows); $html = <<<ADMIN_HEADER {$this->header($subhead)} <table class="adminlist" width="100%"> <thead> <tr> <th width="3%" class="title"> <input type="checkbox" name="toggle" value="" onclick="checkAll($rowcount);" /> </th> <th> {$this->T_('ID')} </th> <th width="50%" class="title"> {$this->T_('Title')} </th> <th> {$this->T_('Byline')} </th> <th> {$this->T_('Hits')} </th> <th align="left"> {$this->T_('Published')} </th> </tr> </thead> <tbody>ADMIN_HEADER; $i = $k = 0; foreach ($rows as $i=>$row) { if ($showlinks) $title = <<<LINK_TITLE <a href="{$this->optionurl}&amp;task=edit&amp; id=$row->id">$row->title</a>LINK_TITLE; else $title = $row->title; $html .= <<<END_OF_BODY_HTML <tr class="row$k"> <td> {$this->html('idBox', $i, $row->id)} </td> <td align="center"> $row->id </td> <td> $title </td> <td> $row->byline </td> <td align="center"> $row->hits </td> <td align="center"> {$this->html('publishedProcessing', $row, $i )} </td> </tr>END_OF_BODY_HTML; $i++; $k = 1 - $k; } if (0 == $rowcount) $html .= <<<NO_ITEMS_HTML <tr><td colspan="6" class="center"> {$this->T_('No items')} </td></tr>NO_ITEMS_HTML; $html .= <<<END_OF_FINAL_HTML </tbody> </table> {$this->pageNav->getListFooter()}END_OF_FINAL_HTML; return $html; } When it comes to adding a new item or editing an existing one, no looping is required, and the WYSIWYG editor is activated to provide a helpful interface for the administrator who is editing a text item. Note that the use of PHP heredoc allows the XHTML to be written out quite plainly, with the PHP insertions unobtrusive but effective. Actual text for translation is shown in its correct place (in the base language) by using the T_ method that is inherited from aliroBasicHTML via basicAdminHTML. public function edit ($text) { $subhead = $text->id ? 'ID='.$text->id : T_('New'); $editor = aliroEditor::getInstance(); echo <<<EDIT_HTML {$this->header($subhead)} <div id="simpletext1"> <div> <label for="title">{$this->T_('Title')}</label><br /> <input type="text" name="title" id="title" size="80" value="$text->title" /> </div> <div> <label for="byline">{$this->T_('Byline')}</label><br /> <input type="text" name="byline" id="byline" size="80" value="$text->byline" /> </div> <div> <label for="version">{$this->T_('Version')}</label><br /> <input type="text" name="version" id="version" size="80" value="$text->version" /> </div> <div> <label for="article">{$this->T_('Article text')}</label><br /> {$editor->editorAreaText( 'article', $text->article, 'article', 500, 200, 80, 15 )} </div> </div> <div id="simpletext2"> <fieldset> <legend>{$this->T_('Publishing')}</legend> <div> <label for="published">{$this->T_('Published')}</label><br /> <input type="checkbox" name="published" id="published" value="1" {$this->checkedIfTrue($text->published)} /> </div> <div> <label for="publishstart">{$this->T_('Start date')}</label><br /> <input type="text" name="publish_start" id="publishstart" size="20" value="$text->publish_start" /> </div> <div> <label for="publishend">{$this->T_('End date')}</label><br /> <input type="text" name="publish_end" id="publishend" size="20" value="$text->publish_end" /> </div> </fieldset> <fieldset> <legend>{$this->T_('Metadata')}</legend> <div> <label for="metakey">{$this->T_('Keys')}</label><br /> <textarea name="metakey" id="metakey" rows="4" cols="40">$text->metakey</textarea> </div> <div> <label for="metadesc">{$this->T_('Description')}</label><br /> <textarea name="metadesc" id="metadesc" rows="4" cols="40">$text->metadesc</textarea> </div> </fieldset> <input type="hidden" name="task" value="" /> $this->optionline </div> <div id="simpletext3"> <input type="hidden" name="id" value="$text->id" /> <input type="hidden" name="boxchecked" value="0" /> <input type="hidden" name="hidemainmenu" value="0" /> </div>EDIT_HTML; } Finally, there is a common method to deal with the creation of the heading. It uses the addCSS method provided by the parent class to link to a small amount of CSS that is held in a separate file. Although the list of text items defined in the XHTML above is perfectly legitimate as a table, since it really is a tabular structure, the heading would be better built out of other XHTML elements. The only reason for using a table here is that it is one of the features retained from earlier systems for the sake of backwards compatibility: private function header ($subhead='') { $this->addCSS(_ALIRO_ADMIN_DIR.'/components /com_text/admin.text.css'); if ($subhead) $subhead = "<small>[$subhead]</small>"; return <<<HEAD_HTML <table class="adminheading"> <tr> <th class="user"> {$this->T_('Simple Text')} $subhead </th> </tr> </table>HEAD_HTML; } }
Read more
  • 0
  • 0
  • 2309
article-image-creating-shopping-cart-using-zend-framework-part-2
Packt
27 Oct 2009
15 min read
Save for later

Creating a Shopping Cart using Zend Framework: Part 2

Packt
27 Oct 2009
15 min read
Creating the Cart Views and Forms Now that we have our Model and Controller created, we can now start putting everything together and get the cart working. Cart forms The Cart will use two forms Storefront_Form_Cart_Add and Storefront_Form_Cart_Table. The add form is displayed next to the products so users can add items to the Cart, and the table form is used to display all the items in the cart so users can edit them. Add form The add form can be used by customers browsing the store to quickly add items to their shopping cart. This form will look like the one shown in the screenshot below when it is rendered: Let's add the code to create the add form now. application/modules/storefront/forms/Cart/Add.php class Storefront_Form_Cart_Add extends SF_Form_Abstract { public function init() { $this->setDisableLoadDefaultDecorators(true); $this->setMethod('post'); $this->setAction(''); $this->setDecorators(array( 'FormElements', 'Form' )); $this->addElement('text', 'qty', array( 'decorators' => array( 'ViewHelper' ), 'style' => 'width: 20px;', 'value' => 1 )); $this->addElement('submit', 'buy-item', array( 'decorators' => array( 'ViewHelper' ), 'label' => 'Add to cart' )); $this->addElement('hidden', 'productId', array( 'decorators' => array( 'ViewHelper' ), )); $this->addElement('hidden', 'returnto', array( 'decorators' => array( 'ViewHelper' ), )); } } The add form contains four elements—qty, buy-item, productId, and returnto. We can see that it is much like the other forms we have created previously. The only major difference here is that we use the setDisableLoadDefaultDecorators() method to disable the default decorators for the form (not the elements). We do this because we do not want the form to contain the default definition list markup (<dl>). We also only use the ViewHelper decorator on each element so that the <dt> and <dd> tags are omitted Table form The table form is going to form the customer shopping cart. Customers will use this form to view, update, and remove items from their cart. This form will look similar to the one showed below when it is rendered: Let's add the code for the table form now: application/modules/storefront/forms/Cart/Table.php class Storefront_Form_Cart_Table extends SF_Form_Abstract { public function init() { $this->setDisableLoadDefaultDecorators(true); $this->setDecorators(array( array( 'ViewScript', array('viewScript' => 'cart/_cart.phtml') ), 'Form' )); $this->setMethod('post'); $this->setAction(''); $this->addElement('submit', 'update-cart', array( 'decorators' => array( 'ViewHelper' ), 'label' => 'Update' )); } } Th e table form is highly specialized. Therefore, we have chosen to use a ViewScript decorator. To do this, we fi rst disable the default decorators using the setDisableLoadDefaultDecorators(). We then need to configure the forms decorators. We will only have two decorators for the form, ViewScript and Form. This means that if we render the form, the update-cart element will not be rendered because we have not included the FormElements decorator. This is where the ViewScript decorator comes in. We can use this decorator to render a View script, in this case cart/_cart.phtml. We then have access to all the elements within the form inside this View script, meaning we can create highly specialized markup without needing to use lots of complicated decorators. Also, the table form will need to have fi elds dynamically added to it as we need a form element for each cart item. We will look at this shortly when we create the View Helper and Views for the Cart. The ViewScript decorator uses a View Partial to render its view script. This has an overhead as it clones the view instance. Generally, partials should be avoided in large numbers so do not over use them or the ViewScript decorator. SF_Form_Abstract You may have noticed that our forms did not subclass Zend_Form as in our previous examples. Also, this time we have extended from the SF_Form_Abstract class. This is because we have done some minor refactoring to the SF library so that we can inject the Model into the form. library/SF/Form/Abstract.php class SF_Form_Abstract extends Zend_Form { protected $_model; public function setModel(SF_Model_Interface $model) { $this->_model = $model; } public function getModel() { return $this->_model; } } The new SF_Form_Abstract class subclasses Zend_Form and adds two new methods, setModel() and getModel(). These simply set, and get, the protected $_model property. This then means that when we instantiate the form, we can pass in the model inside the options array. $form = new SF_Form_Abstract(array('model' => new myModel())); Here we are taking advantage of the fact that the setOptions() method will look for setters that match elements in the options array. In our case, the setOptions() class will find the setModel() method, call it, and pass in the model. This type of functionality is very common in Zend Framework components. It is always worth checking the setOptions() methods on components to see if you can extend them in this way. To get the model injected on instantiation, we also need to make a minor change to the SF_Model_Abstract. library/SF/Model/Abstract.php public function getForm($name) { if (!isset($this->_forms[$name])) { $class = join('_', array( $this->_getNamespace(), 'Form', $this->_getInflected($name) )); $this->_forms[$name] = new $class( array('model' => $this) ); } return $this->_forms[$name]; } He re, we simply pass in an array containing the model ($this) when we first instantiate the form class. We now have access to our Model from within our forms. Cart View Helper Th e Cart View Helper is responsible for creating many of the display elements for the cart. Therefore, we will break it down and look at each method in turn. application/modules/storefront/views/helpers/Cart.php class Zend_View_Helper_Cart extends Zend_View_Helper_Abstract { public $cartModel; public function Cart() { $this->cartModel = new Storefront_Model_Cart(); return $this; } The main Cart() method instantiates a new Cart Model and then returns a reference to itself so that we can chain calls to the other methods. application/modules/storefront/views/helpers/Cart.php public function getSummary() { $currency = new Zend_Currency(); $itemCount = count($this->cartModel); if (0 == $itemCount) { return '<p>No Items</p>'; } $html = '<p>Items: ' . $itemCount; $html .= ' | Total: '.$currency->toCurrency ($this->cartModel->getSubTotal()); $html .= '<br /><a href="'; $html .= $this->view->url(array( 'controller' => 'cart', 'action' => 'view', 'module' => 'storefront' ), 'default', true ); $html .= '">View Cart</a></p>'; return $html; } The getSummary() method creates the HTML that will be used to display a summary of the cart items and subtotal to the user. This will be displayed below the main category menus. application/modules/storefront/views/helpers/Cart.php public function addForm(Storefront_Resource_Product_Item$product) { $form = $this->cartModel->getForm('cartAdd'); $form->populate(array( 'productId' => $product->productId, 'returnto' => $this->view->url() )); $form->setAction($this->view->url(array( 'controller' => 'cart', 'action' => 'add', 'module' => 'storefront' ), 'default', true )); return $form; } The addForm() method will return a form for adding a single product to the cart. This method accepts one parameter $product that must be an instance of Storefront_Resource_Product_Item. We will use this to render individual add to cart forms for each product. application/modules/storefront/views/helpers/Cart.php public function cartTable() { $cartTable = $this->cartModel->getForm('cartTable'); $cartTable->setAction($this->view->url(array( 'controller' => 'cart' , 'action' => 'update' ), 'default' )); $qtys = new Zend_Form_SubForm(); foreach($this->cartModel as $item) { $qtys->addElement('text', (string) $item->productId, array( 'value' => $item->qty, 'belongsTo' => 'quantity', 'style' => 'width: 20px;', 'decorators' => array( 'ViewHelper' ), ) ); } $cartTable->addSubForm($qtys, 'qtys'); // add shipping options $cartTable->addElement('select', 'shipping', array( 'decorators' => array( 'ViewHelper' ), 'MultiOptions' => $this->_getShippingMultiOptions(), 'onChange' => 'this.form.submit();', 'value' => $this->cartModel->getShippingCost() )); return $cartTable; } The cartTable() method will return the table containing all our cart items, their costs, and totals. This will be used to update items in the cart. We create a subform to dynamically add the cart items quantity elements at runtime. The reason we use a subform is so we can easily get the whole set of quantity fi elds from the form, and later iterate over them in the View script. The form will need to contain an array of quantity text elements so that we can iterate over them in the updateAction in the controller. To create this array, we pass the belongsTo option to the addElement() method, which will tell the form that these elements are an array with the name quantity. We also set the value of the element to the qty held in the cart item. We also need a way of passing the productId for each cart item. To do this, we set the element name to the productId of the item. This also helps us by providing a unique name for each element (we have to cast this to a string). It will create a set of text form elements like: <input type="text" style="width: 20px;" value="1" id="quantity-21"name="quantity[21]"/><input type="text" style="width: 20px;" value="5" id="quantity-10"name="quantity[10]"/> Once we have all the quantity elements in the subform, we then add the whole subform to the main table form using the addSubForm() method. We give this the name of qtys, which we will use in the View script later to retrieve the elements. We also add the shipping options to the main table form. Here, we use the _getShippingMultiOptions() method to populate the select elements options and set the value to the currently selected shipping option of the cart. application/modules/storefront/views/helpers/Cart.php public function formatAmount($amount) { $currency = new Zend_Currency(); return $currency->toCurrency($amount); } The formatAmount() method is a little helper method we use to display amounts from the Cart. This may not be necessary in the future as there is a proposal for a currency View Helper that we would use instead. application/modules/storefront/views/helpers/Cart.php private function _getShippingMultiOptions() { $currency = new Zend_Currency(); $shipping = new Storefront_Model_Shipping(); $options = array(0 => 'Please Select'); foreach($shipping->getShippingOptions() as $key => $value) { $options["$value"] = $key . ' - ' . $currency->toCurrency($value); } return $options; } } Our final method is the private _getShippingMultiOptions() method. This is used internally by the cartTable() method to populate the shipping select element's options. This method gets the shipping options from the Shipping Model and creates an array suitable for the multiOptions option. Cart View scripts Now that we have all the tools created that we will need to build our cart, we can start creating the user interface. Cart view.phtml The view.phtml is the View that is rendered by the viewAction of the CartController. This View includes a title and renders the cartTable form application/modules/storefront/views/scripts/cart/view.phtml <h3>shopping <span>cart</span></h3> <?=$this->Cart()->cartTable();?> Cart _cart.phtml The ViewScript decorator attached to the table form will render the _cart.phtml View. When it renders, the ViewScript decorator will create a view partial and pass in the form as the element property for this View script. application/modules/storefront/views/scripts/cart/_cart.phtml <div style="padding: 8px;"> <table style="width: 100%;"> <tbody> <? $i = 0; foreach($this->element->getModel() as $item): ?> <tr <? if($i % 2){ echo 'class="odd"';};?>> <td><?=$this->Escape($item->name); ?></td> <td><?=$this->element->qtys->getElement ($item->productId); ?></td> <td class="rt"><?=$this->Cart()->formatAmount ($item->getLineCost()); ?></td> </tr> <? ++$i; endforeach; ?> <tr> <td colspan="2" class="rt">SubTotal:</td> <td class="rt colRight"><?=$this->Cart() ->formatAmount($this->element->getModel() ->getSubTotal()); ?></td> </tr> <tr> <td colspan="2" class="rt">Shipping: <?=$this->element ->getElement('shipping');?></td> <td class="rt colRight"><?=$this->Cart() ->formatAmount($this->element->getModel() ->getShippingCost()); ?></td> </tr> <tr> <td colspan="2" class="rt">Total:</td> <td class="rt"><?=$this->Cart()->formatAmount($this ->element->getModel()->getTotal()); ?></td> </tr> </tbody></table><?=$this->element->getElement('update-cart'); ?></div> The HTML produced by this script will look similar to the following screenshot: The main aspect here is the line items. We need to iterate over the cart and display each product line item. <?$i = 0;foreach($this->element->getModel() as $item):?> <tr <? if($i % 2){ echo 'class="odd"';};?>> <td><?=$this->Escape($item->name); ?></td> <td><?=$this->element->qtys->getElement($item->productId); ?> </td> <td class="rt"><?=$this->Cart()->formatAmount($item->getLineCost()); ?> </td> </tr><?++$i;endforeach;?> Here, we get the Cart Model from the form using our new getModel() method that we created earlier in the SF_Form_Abstract and iterate over it. As we iterate over the Cart Model, we display all the products and line costs. We also get the quantity form elements. To retrieve the correct quantity form element for each product, we access the qtys subform and use the getElement() method. We pass in the items productId as we named our quantity form elements using the productId earlier. All of the other form data is rendered in a similar way. We either get data from the Cart Model, or get elements from the form itself. By using the ViewScript decorator, we can see that it is much easier to mix form and non-form elements. Layout main.phtml application/layouts/scripts/main.phtml <div class="left categorylist"> <?= $this->layout()->categoryMain; ?> <? if (0 < count($this->subCategories)):?> <div class="sub-nav"> <h3>in this <span>category</span></h3> <ul> <? foreach ($this->subCategories as $category): ?> <li><a href="<?=$this->url(array('categoryIdent' => $category->ident), 'catalog_category', true );?>"><?=$category->name; ?></a></li> <? endforeach; ?> </ul> </div> <? endif; ?> <div> <h3>in your <span>cart</span></h3> <?= $this->Cart()->getSummary(); ?> </div> </div> We need to display the cart summary to the users so that they can see a brief overview of the items in their cart. To do this, we will use the Cart View Helper and the getSummary() method that looks similar to the following screenshot: Catalog index.phtml application/modules/storefront/view/scripts/catalog/index.phtml <p><?=$this->productPrice($product); ?></p> <?=$this->Cart()->addForm($product); ?> When displaying a list of products, we want the user to be able to add the product to their cart at that point. To do this, we render the cart add form under the price. This will make our catalog listing look like the one shown below: Catalog view.phtml application/modules/storefront/view/scripts/catalog/view.phtml <p><?=$this->productPrice($this->product); ?></p> <?=$this->Cart()->addForm($this->product); ?> Just like the index.phtml, we need to render the cart add form after the product price. This will make our details page look like this: Summary In this two-part article series, we learnt about: Creating Models that do not use a database as a data source Using Zend_Session_Namespace Implementing the Cart Views and Controllers More Forms, View Helpers, and so on If you have read this article you may be interested to view : Creating a Shopping Cart using Zend Framework: Part 1
Read more
  • 0
  • 0
  • 3897

article-image-adding-worksheets-and-resources-moodle
Packt
27 Oct 2009
12 min read
Save for later

Adding Worksheets and Resources with Moodle

Packt
27 Oct 2009
12 min read
We're teaching the topic of Rivers and Flooding; so to start with, we'll need to introduce our class to some basic facts about rivers and how they work. We aren't going to generate any new stuff yet; we're just going to upload to Moodle what we have already produced in previous years. Putting a worksheet on Moodle The way Moodle works is that we must first upload our worksheet into the course file storage area. Then, in that central section of our course page, we make a link to the worksheet from some appropriately chosen words. Our students click on these words to get to the worksheet. We've got an introductory factsheet (done in Word) about the River Thames. Let's get it into Moodle: Time for action-uploading a factsheet on to Moodle We need to get the worksheet uploaded into Moodle. To get this done, we have to follow a few simple steps. Go to your course page and click on the Turn editing on button, as shown in the following screenshot: Don't worry about all of the new symbols (icons) that appear. In the section you want the worksheet to be displayed, so look for these two boxes: Click on the Add a resource box (I'll go through all its options when we have a recap, later). Select a link to a file or web site. In Name, type the text that you want the students to click on, and in Summary (if you want) add a short description. The following screenshot gives an example of this: Once you're done with the above steps, click on Choose or upload a file. This takes you to the course files storage area. Click on Make a folder, and in the dialog box that is displayed, choose a suitable name for the folder all your worksheets will be stored in (we'll use Worksheets). Click on Create. Click on the folder that you just created (It will be empty except for Parent Folder, which takes you back to the main course files). Click on Upload a file. You'll be prompted to browse your computer's hard drive for the worksheet. Find the worksheet, select it with your cursor and click Open. It will appear as shown in the following screenshot: Click Upload this file. Once the file has been uploaded, it will appear as shown in the following screenshot: What just happened? We just uploaded our first ever worksheet to Moodle. It's now in the course files. Next, we need to make a link on the page that students can click on to get to that worksheet. I know what you're thinking! Thirteen steps, and there's still no sign of our River Thames worksheet on the course page in Moodle. Is it going to be this long-winded every time? Don't worry! There are only two—at worst three—steps left . And although it seems to be a lot of effort the first time, it gets much quicker, as we move on. We are also trying to be organized from the start by putting our worksheets neatly into a folder, so we took a couple of extra steps that we won't have to do next time. The folder will already be there for us. Ofcourse, you can just click on Upload a file and get your worksheets straight into the course files without any sort of order, and they will display for your students just as well. But when you have a lot of worksheets loaded, it will become harder and harder to locate them unless you have a system. Time for action-displaying our factsheet on our course page To get the Moodle course started, we need to create a link that—when clicked, will get the course started, carrying on from where we left off : Click on the word Choose to the right of your worksheet. (We are choosing to put this on Moodle.) The River Thames worksheet now shows in the Location box, under Link to a file or web site. We are almost there! Scroll down and make sure that you have selected the New window option in theWindow box, as shown in the following screenshot: At the bottom of the screen, click on Save and return to course. Done! The option Search for web page would take you to Google or another search engine to find a web site. You could put that web site into the location box instead, and it would make a clickable link for your students to follow. What just happened? Congratulations! You’ve now made a link to the factsheet about the River Thames that will get our Rivers and Flooding course started! By doing the final step above, we will get taken back to the course page where we'll see the words that we wrote in the Name box. They'll be in blue with a line underneath. This tells us it's a clickable link that will take us to the factsheet. If you can do that once, you can do it many times. Have a go hero-putting a slideshow onto Moodle It's important to go through the steps again, pretty quickly, so that you become familiar with them and are able to speed the process up. So why not take one of your slide shows (maybe done in PowerPoint) and upload that to Moodle? Start by creating a folder called Slideshows, so that in future, it will be available for any slideshows that you upload. Or, if you're too tired, just upload another sheet into our Worksheets folder and display that.   Putting a week's worth of slideshows into Moodle Now let's suppose that we have already prepared a week's worth of slideshows. Actually, I could say, a month's worth of worksheets, or a year's worth of exam papers. Basically, what we're going to do is upload several items, all at once. This is very useful because once you get used to uploading and displaying worksheets, you will very quickly start thinking about how tedious it would be, to put them on Moodle one at a time. Especially if you are studying ten major world rivers, and you have to go through all of those steps ten times. Well, you don't! Let's use my River Processes slideshows as our example. I have them saved in a folder on My Computer (as opposed to being shoved at random in a drawer, obviously!). Under normal circumstances, Moodle won't let you upload whole folders just like that. You have to either compress or zip them first (that basically means squeeze it up a bit, so it slides into cyberspace more smoothly). We first need to leave Moodle for a while and go to our own computer. I'm using Windows; for Macs, it will be slightly different. Time for action-getting a whole folder of work into Moodle in one go To view the slideshows, we need to upload the folder containing them from the hard drive of our computer into Moodle. Find the folder that you want to upload, right-click on it, and select Compressed (zipped) Folder within the Send To option. You'll get another folder with the same name, but in ZIP format. Go to your Moodle course page, and in the Administration box, click Files. We're in the course files storage area—this is another way in, if you ever need one! You can upload anything straight into here, and then provide a link to a file or web site. As we have done before, click on Upload and upload the zipped folder (it ends in .zip). Now click on Unzip, which is displayed to the right of your folder name (as shown in the following screenshot), and the folder will be restored to its normal size. What just happened? We put a bunch of slideshows about how rivers work into a folder on our computer. We then zipped the folder to make it slide into Moodle, and then when it was uploaded, we unzipped it to get it back to normal. If you want to be organized, select the checkbox displayed to the left of the zipped folder, and select delete completely. We don't need the zipped folder now, as we have got the original folder back. We now have two choices. Using the Link to a file or web site option in the Add a resource block, we can display each slideshow, in an orderly manner, in the list. We did this with our Thames factsheet, so we know how to do this. Alternatively, we can simply display the folder and let the students open it to get to the slideshows. We're going to opt for the second choice. Why? Bearing in mind about appearances being vital, it would look much neater on our course page if we had a dinky little briefcase icon. The student can click on the briefcase icon to see the list of slideshows, rather than scrolling down a long list on the page. Let us see how this is done: Time for action-displaying a whole folder on Moodle Let us upload the entire folder, which contains the related slideshows, onto Moodle. This will require us to perform only four steps: With editing turned on, click on Add a resource and choose Display a directory. In the Name field, type something meaningful for the students to click on and add a description in the Summary field, if you wish. Click on Display a directory and find the one that you want—for us, RiverProcesses. Scroll down, and click on Save and return to course. What just happened? We made a link to a week's worth of slideshows on our course page, instead of displaying them one at a time. If we looked at the outcome, instead of the icon of a slideshow, such as the PowerPoint icon, we get a folder icon. When the text next to it is clicked, the folder opens, and all of the slideshows inside can be viewed. It is much easier on the eye, when you go directly to the course page, than going through a long list of stuff . Making a 'click here' type link to the River Thames web site Let's learn how to create a link that will lead us to the River Thames web site, or in fact to any web site. However, we're investigating the Thames at the moment, so this would be really helpful. Just imagine, how much simpler it would be for our students to be able to get to a site in one click, rather than type it by hand, spell it wrong, and have it not work. The way we will learn now is easy. In fact, it's so easy that you could do it yourself with only one hint from me. Have a go hero-linking to a web site Do you recollect that we uploaded our worksheet and used Link to a file or web site? We linked it to a file (our worksheet). Here, you just need to link to a web site, and everything else is just the same. When you get to the Link to a file or web site box, instead of clicking Choose or upload a file…, just type in, or copy and paste, the web site that you want to link to (making sure you include only one http://). Remember that we saw earlier, that if you click on Search for web page…, it will take you to Google or some other Search Engine web page to find you a web site that you'd like to link to. The following screenshot shows how to link a file or web site into our Moodle course : That's it! Try it! Go back to your course page; click on the words that you specified as the Name for the web page link, and check whether it works. It should open the web page in a new window, so that once finished, our students can click on the X to close the site and will still have Moodle running in the background. Recap—where do we stand now? We have learnt a lot of interesting things so far. Lets just have a recap of the things that we have learned so far. We have learnt to: Upload and display individual worksheets (as we've worked on the River Thames) Upload and display whole folders of worksheets (as we did with the River Processes slideshows folder) Make a click here type link to any web site that we want, so that our students will just need to click on this link to get to that web site We're now going to have a break from filling up our course for a while, and take a step to another side. Our first venture into Moodle's features was the Link to a file or web site option, but there are many more yet to be investigated. Let's have a closer look at those Add a resource… options in the following screenshot, so that we know, where we are heading: The table below shows all of the Add a Resource… options. What are they, which is the one we need, and what can we safely ignore? You might recognize one or two already. We shall meet the others in a moment.
Read more
  • 0
  • 0
  • 3055
Modal Close icon
Modal Close icon