Tuesday, February 14, 2012

Using Msysgit and Connect on Windows to work with fluxflex.com via a proxy

Before you do this, ask yourself the following question. Why?
No seriously.

  Why?

Now that you've convinced yourself that you are too lazy to install a copy of Linux, let's move on.

The instructions below explain how to do this at the University of the West Indies Mona campus using one of their internal proxies (scalpel,proxy-cluster,proxy3, razor or sword). All of these proxies run on port 8080, if you are using a different proxy and a different port you will need to adjust the instructions accordingly.

Preparation:
1. Install MsysGIT http://code.google.com/p/msysgit/
2. Download connect.exe and place it in your Windows folder (probably c:\Windows) http://dl.dropbox.com/u/1004432/connect.exe
3. Configure ssh to work via the proxy. The steps are detailed below

Configuring SSH/Git to work behind a proxy
Launch git bash:


You will see something like this:
Make sure that the 'connect' command is installed by entering the command 'connect'. You should see something like this:
If the connect command does not work go back to step 2 and make sure you get installed.

Next we need to create our shared keys, you can use the following command:

      ssh-keygen

You should get the following output (press enter at all questions, there is no need for a passphrase):

Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/David.David-TempPC/.ssh/id_rsa):

Enter passphrase (empty for no passphrase):

To check that your key has been properly generated use command:

   notepad  ~/.ssh/id_rsa.pub

You will see something like this:
You'll need this later (yes it is supposed to be a single line!, unless you turn on text wrapping).

When you close notepad you will be returned to gitbash.

To create a new ssh config file we will run the following commands:

     touch ~/.ssh/config
     notepad ~/.ssh/config

Enter the following text in notepad then save and exit it:

Host *
   ProxyCommand connect.exe -H scalpel:8080 %h %p


That's it.
Warning (this configuration means that msysgit will not work when you are not behind this proxy)
Just remove the ProxyCommand or comment it out when you are not behind a proxy.

Day to day usage:
Just launch gitbash and use it, git and ssh should work (at UWI this requires communicating with servers that run on port 443, we'll look at fluxflex (a service that runs ssh/git as a service on port 443)

Signing up with Fluxflex.com:  
Register an account with http://fluxflex.com
../_images/flux-new-project.png

Registering a Public Key with Fluxflex.com

You will have already created your public key. 
Launch gitbash and run the following command:
     notepad  ~/.ssh/id_rsa.pub

Copy the text that shows up in notepad:

 Then paste the resulting output to your fluxflex key list by going to “Plan & Settings” > “Public Keys” > “SSH Public Keys List” and click “Save”.
../_images/fluxflex-add-key.png

 Starting a new project with Fluxflex
The following instructions assume that you have configured the proxy and the shared keys, they are based on the standard fluxflex instructions.
  1. Log in to your fluxflex account and “create a new project”. 
  1. You can check out your new project by name using git. 
    Launch gitbash and clone your project. For example if your project is called yourprojectname:
    git clone ssh://git@git.fluxflex.com:443/yourprojectname

    If you want to confirm the proper procedure, go to “Setup” > “Git” and copy the code for downloading your project.
../_images/flux-gitsetup.png







Thursday, February 9, 2012

Installing Flask on Windows using Bootstrapflask.py

For a course that I'm teaching, I created bootstrapflask.py, it was meant to make it possible to install Flask quickly on any OS.

The usage steps are as follows:

  1.   Run it:
        python bootstrapflask.py
  2. Launch it. From the directory where you ran the bootstrap launch the helloflask.py program (note on Windows, bootstrapflask.py creates a 'Scripts' directory):
         venv/Scripts/python helloflask.py
    
    


Saturday, January 14, 2012

Dexterity Development Quickstart using zopeskel.dexterity

These are my notes for getting started quickly with dexterity and zopeskel.dexterity.

Rule Number One: Use Unix
This is about getting started quickly. At this time, Windows will slow you down, do this on a server or something, this issue may change in the future at which point I will be able to recommend otherwise, but for now, for the sake of your sanity just use OS X or Linux for development.

Rule Number Two: Use the Unified Installer
The Unified Installer (usually available at http://plone.org/download) provides all the tools you need to get started, everything here assumes that you have successfully installed Plone via the Unified Installer on your platform.

Rule Number Three: 
Install your app and run buildout BEFORE attempting to use localcommands. This is important because additional "goodness" is added to your new package when it is properly installed to your instance.

Step 1 - Install via the UnifiedInstaller then edit the base.cfg and add zopeskel.dexterity

eggs =
    PasteScript
    ZopeSkel
    zopeskel.dexterity

Then re-run buildout 
    bin/buildout
 Step 2 - Create your first product
cd src
../bin/zopeskel dexterity my.app

WARNING: localcommands like "addcontent" WILL NOT WORK until you install the app and run buildout!

Step 3 - Install your app by adding it to the buildout.cfg and re-run buildout

Add the following lines to your buildout.cfg
eggs =  
        my.app 
develop =
                 src/my.app

or if you prefer to use mr.developer do something like this:
extensions = mr.developer
auto-checkout = my.app
....
[sources]
my.app = fs  my.app
The re-run buildout
bin/buildout

Step 4 - Add your first contenttype
Note that all localcommands are run from within your new app
cd src/my.app
../../bin/paster addcontent dexterity_content 

You should now be able to follow the instructions at: http://collective-docs.readthedocs.org/en/latest/content/dexterity.html

If you want to know what localcommands are available try running
../../bin/paster addcontent -l
Activate your new Add-on
To see if everything is working launch your instance and visit Site Setup > Add-ons, you should now be able to activate your new add-on.


In the screenshot below, I have already created a content type for my add-on, so after activation I can use the green content bar in my site to add a new example type.




Thursday, November 3, 2011

Common Diazo Rules for Plone

Here is a list of useful rules for your Diazo theming needs.

Common Plone Specific Diazo Rules


Adding the main plone content to a specific container
<prepend css:theme="#container" css:content="#portal-columns"/>


Ensure that the body tag inherits Plone classes
<!-- BODY THEME (inject body classes from Plone into the theme) -->
     <copy attributes="*" css:theme="body" css:content="body" />
Replace the theme title and base tags in the head (including styles from the Plone site)
    <!-- Base tag -->
    <replace theme="/html/head/base" content="/html/head/base" />
    <!-- HEAD: title -->
    <replace theme="/html/head/title" content="/html/head/title" />
   <before theme="/html/head" content="/html/head" />
To prevent the theme from affecting the Zope Management Interface (ZMI) and most popups you can use the following 'rules' filter to only enable the theme when there is a visual portal wrapper present in the markup:
<rules css:if-content="#visual-portal-wrapper">
        <theme href="index.html" />
</rules>
Add Login and Personal Tools
<!-- ADD LOGIN/Personal Tools  -->
    <prepend content='//*[@id="portal-personaltools"]' theme='//*[@id="header"]' />
Ensure that tinymce popups remain unstyled
 <notheme if-path="presentation_view"/>
    <notheme if-path="source_editor.htm"/>
    <notheme if-path="ploneimage.htm"/>
    <notheme if-path="anchor.htm"/>
    <notheme if-path="table.htm"/>
    <notheme if-path="attributes.htm"/>
Edit Bar provides the green content bar. Prevent unwanted styling to the edit bar by adding the #edit-bar before the content of your theme. If the main content area is #contentBlock then something like this:
<before css:content="#edit-bar" css:theme="#contentBlock"/>
 Use method="raw" to force a rule to work even after the selector has been dropped by another rule. In the example below the viewlet has been dropped from the content but it is still added back to the theme using a replace with the method="raw".
<drop css:content="#viewlet-above-content"/>
<replace method="raw" css:theme="#top-viewlet-holder" css:content="#viewlet-above-content"/>
 Append the <script> tag at the bottom of your theme (this example appends the scripts to a div with id 'footer', this is important to ensure that analytics or other javascript based includes show up in the theme.
<append content='//*[@id="visual-portal-wrapper"]/script' theme='//*[@id="footer"]'/>

 Using XSL with Diazo

If you need more logic try setting and using variables (requires use of XSL)
 <xsl:variable name="carousel" css:select="body .carouselWrapper"/>
   <rules if-content="not($carousel)">
      <drop css:theme="#header" />
   </rules>
Here's an example of dynamically inserting a new class based on the existence of another class called 'carousel', the space before the word 'carousel' is needed.
<prepend theme="/html/body" css:if-content="body.section-home">
                <xsl:attribute name="class"><xsl:value-of select="/html/body/@class"/> carousel</xsl:attribute>
</prepend>

Thursday, October 27, 2011

Tag multiple items at once in a Plone site

One feature that I'm looking for in my Plone sites is the ability to add new tags to multiple items at once. This could be achieved in the folder_contents view, perhaps with a new button called "categorization" (similar to the "change state" button).

Global expiration date for Plone sites

Wouldn't it be nice to have a little control panel that configures a default global expiration date for content?

To make it better it should be granular enough to vary default expiration dates by content type.

Sunday, October 23, 2011

Weekend Project: Image Thumbnailer - Day 2


Day 2

6:18 am - Rendering output as JSON

Javascript Object Notation (JSON) is almost expected nowadays when deploying an API. Pyramid has a convenient approach to doing this, by providing a renderer called 'json'.
I edited my view information under 'imageuploadr/__init__.py' so that it now looks like this:

The result is that the response is rendered as JSON.
When viewed using Chrome the output is displayed in the browser. If you use Firefox you will, most likely, be prompted to download the result as a text file.
 Here is how it looks in Chrome.

9:05 am  - File uploads

After lots of tangents reading up on the features of Pyramid, I've been able to track down a useful resource on working with files. I haven't tried this yet and may have to put it off for a few hours but this is next on my reading list:
http://docs.pylonsproject.org/projects/pyramid_cookbook/dev/files.html#basic-file-uploads
  • Added a simple form to my template
  • Switched the renderer from json back to my template
The new form code was added templates/mytemplate.pt and looks like this:
  <form action="/process_image" method="post" accept-charset="utf-8"
      enctype="multipart/form-data">
    <label for="image">Image</label>
    <input id="image" name="image" type="file" value="" />
    <input type="submit" value="submit" />
</form>
Note the action 'process_image' which will call a view called process_image does not exist yet (adding it to my todo list).
Here's a screenshot:

Many things to do and get done

So no coding until this evening.

9:33 pm - Implementing process_image

In order to support image processing I decided to make use of the standard library uuid for generation of unique names and Pillow (a setuptools friendly, fork of the Python Imaging Library).

 Since Pillow is not part of the standard library I had to list it as a dependency by adding it to the requires list of the setup.py file.
requires = ['pyramid', 'pyramid_debugtoolbar','Pillow']
Then I had to re-run the setup.py develop command:
python setup.py develop
  My views.py file now has 3 new functions (only one of them 'process_image' will become a new view though. I also decided to use the @view_config decorators that Pyramid provides, the resulting code:
import os
import uuid
from os.path import basename, splitext
from pyramid.response import Response
from pyramid.view import view_config
from PIL import Image


@view_config(context='imageuploadr:resources.Root',renderer='imageuploadr:templates/mytemplate.pt')
def my_view(request):
    return {'project':'imageuploadr',
              }

@view_config(renderer='json',name='process_image')
def process_image(request):
    filename = request.POST['image'].filename

    input_file = request.POST['image'].file
    # I generate a new file name using uuid
    newname = str(uuid.uuid1()) + splitext(filename)[-1]
    file_path = os.path.join('/tmp', newname)
    output_file = open(file_path, 'wb')

    # write the data to the output file
    input_file.seek(0)
    while 1:
        data = input_file.read(2<<16)
        if not data:
            break
        output_file.write(data)
    output_file.close()

    new_image = thumbnail_image(file_path)

    return {'f':filename,'newimage':new_image}

def thumbnail_image(image_path):
    thumbname = "/tmp/%s.thumb%s" % splitext(basename(image_path))
    image = Image.open(image_path)
    new_image = image.resize((200, 200), Image.ANTIALIAS)
    new_image.save(thumbname)
    return thumbname

 11:08 pm - Done for now, next steps

That's it, I'm sure I could have gotten this done faster if I didn't have other weekend obligations, and if I didn't spend time documenting my steps (but that would reduce the value of the exercise). The research was fun and it proves that I can get stuff done in the Pyramid Framework. The framework is predictable and well documented, I did overlook a few typos, like this sentence starting with 'THe'

on the http://docs.pylonsproject.org/projects/pyramid/dev/narr/urldispatch.html page.
(update: The typo has been fixed at github)

What next

This is a list of other things I could do with this project.
  • An Ajax Style Interface
  • HTML5 Drag and Drop Upload
  • Mapping the uuid name to the original file name
  • A progress bar during upload
  • Multiple File Upload
  • Add user accounts and authentication
  • A user interface for cropping the uploaded image (or tie it to an api like pixlr or picnik)
  • A website screenshot taker

Closing Thoughts.

Coming from the school of traversal I still need to iron out url dispatch and view configuration. I had a few false starts trying to figure out whether to use @view_config(route_name="....") or @view_config(name="...."), but I managed to get something working with a bit of googling. I'll need to re-read the documentation.
The short project format is more engaging and helps me to learn much better than following the steps of a tutorial, I'll definitely need to do more of these. In the process I've been able to learn a bit more about:
  • Rendering to JSON and other formats with Pyramid
  • Managing File Uploads with Pyramid
  • Interacting with form requests and responses
  • Using form request data in templates
  • Basics of URL Dispatch and view configuration
  • Using the Pyramid Debug Toolbar
  • Processing a file based on a URL
Most useful resource: The Pyramid_Cookbook