Showing posts with label worklog. Show all posts
Showing posts with label worklog. Show all posts

Sunday, June 3, 2012

Worklog source code

The worklog-project can now be found on Bitbucket, https://bitbucket.org/nilsmagnus/worklog .

Wednesday, May 30, 2012

Worklog part 4: Putting my work into the cloud

After having tried cloud-foundry in combination with grails, I can only say that it is the best way I have ever experienced a deployment of a web-app.

What I have to do is:
  • get a cloud-foundry-beta account
  • install the cloud-foundry plugin
  • create a properties-file in my home-catalog/
  • create a database for my app(one-liner)
  • deploy app
  • have a beer

Get the cloud-foundry account from cloudfoundry.com

Then install the cloud-foundry plugin by adding it to your BuildConfig.groovy.

 runtime ":cloud-foundry:1.2.2"
(you should probably check if a newer version is available from here)

The property-file($HOME/.grails/settings.groovy) must contain 2 properties:

grails.plugin.cloudfoundry.user=youruser
grails.plugin.cloudfoundry.password=XXX

Creating a database couldn´t be simpler, to create a plain mysql database, just type

  cf-create-service mysql worklog-db

Deploying the app is even simpler.

  prod cf-push
And there you go. Congrats, the app is deployed. My app is deployed on http://webtimer.cloudfoundry.com/

Have a beer.

Worklog part3: adding some sexy ui

I bet you I know a lot of css. I´ve tried most of the tags, experimented a lot with css3 and so on. But I STILL cannot make a web-page look good. My brain is simply not wired to see what is beautiful, and even less create beautiful pages. So I frequently steal css and need all the help I can get when I´m responsible for a page design.

So therefore, twitter bootstrap is a very good choice for my pages. What I have to do is install some plugins in my app, copy some groovy-code and voilá: good-looking pages, . All I do is following the steps described on this page, except you should use the 1.2 version of fields(':fields:1.2') There you go, twitter bootstrap and nice autogenerated pages for you.

To re-generate the pages for e.g. Company, simply type
grails generate-all worklog.Company
and answer "a" for all on the overwrite-question.

Wednesday, May 16, 2012

Worklog part2: Domain objects and relations in GORM

Last time, we created the domain-class User. Meanwhile I found this name a bit ambiguous, so I renamed it to Employee. In addition to Employee, I need some other domain-objects to support my application. I need a Company, Department, Customer, Project, ProjectExpense, ProjectWorkUnit. And of course these are related in some way or another, leveraging the powers of GORM.
First off, let´s create the domain-classes using the grails interactive mode
// start interactive mode by typing "grails"

# create-domain-class worklog.Employee
# create-domain-class worklog.Company
# create-domain-class worklog.Department
# create-domain-class worklog.Customer
# create-domain-class worklog.Project
# create-domain-class worklog.ProjectExpense
# create-domain-class worklog.ProjectWorkUnit
# create-domain-class worklog.ProjectRole
Now, a company can have several departments. To tell GORM about this relation, I simply use the "hasMany" property in Company, along with some other sane constraints:
package worklog

class Company {

    String domain
    String name
    Date dateCreated

    static hasMany = [ department:Department]

    /**
     * hibernate plugin event-method
     * @return
     */
    def beforeInsert(){
        dateCreated = new Date()
    }

    static constraints = {
        domain(unique: true)
        name(nullable: false)
    }

    String toString(){
        domain
    }
}

By default all properties are non-nullable in GORM, but I like to specify non-nullable constraints I think are important for my domain-class. The "hasMany" keyword tells GORM that Company can have 0 or more departments. The domain-property is unique for each Company, so I added the unique-constraint. Before inserting a new Company into the database, the beforeInsert() method is run by GORM, so I grab the opportunity to put a createdDate on the object.
It´s possible(and necessary) to have several relations declared in the hasMany property. For example, a project can have related both roles, expenses and work-units:
class Project{
  ...
  static hasMany = [projectRoles: ProjectRole, projectWorkUnits:ProjectWorkUnit, projectExpenses:ProjectExpense]
  ...
}
Also, an employee has to know to wich department he/she belongs to, expressed by the belongsTo keyword.
...
class Employee{
  static belongsTo = [department:Department]
}
...
Now, my total domain model is mapped and since I use intellij, a nice drawing of my relations are illustrated like this:


With a nice domain-model in place, I need some test-data to test my app locally. In my Bootstrap.groovy-file there is an init-method. This will be run every time the application starts, so we can add some test-data here. Grails has built-in methods to check for what environment we are in so we don´t create test-data in our production environment.
class BootStrap {

    def init = { servletContext ->
        switch (Environment.current) {
            case Environment.DEVELOPMENT:
                Company webstep = new Company(name: "webster", domain: "webstep.no").save()
                Department oslo = new Department(company: webstep, name: "Konnsulting", city: "Oshlo").save()
                Employee nils = new Employee(department: oslo, email: "nilsmagnus@gmail.com", securityRole: SecurityRole.NORMAL).save()
                Customer icu = new Customer(name: "icu").save()
                Project icuRefactoring = new Project(department: oslo, customer: icu, name: "refactoring legacy code").save()
                ProjectRole developer = new ProjectRole(employee: nils, project: icuRefactoring, hourRate: 1200.0, description: "Develop some cool shait").save()
                ProjectExpense calculatorPurchase = new ProjectExpense(description: "new calculator", project: icuRefactoring, projectRole: developer, amount: 1300.0 ).save()

                break
        }
    }
}
This fills in some data for testing purposes, now we just need to see the data in our app. To get started with ui, I think it´s nice to generate html and controllers with grails using the built in "generate-all" command. For each domain-class I enter the command
# generate-all worklog.Employee
....
# run-app
And its time for inspection :)
To recap: GORM takes care of database-mapping and intellij shows you the relations in your app. Easy as that. Next time: some testing. Later on I will be doing the gorm critierias to create nice reports.

Thursday, May 10, 2012

Worklog part1: Up and running with authentication

Intention of this session: create a User object and use google to log in.

First I need to create my grails app from the command line(assuming I have installed it first)
# grails create-app webtimer

Then enter interactive-mode by typing
# grails 

To create a domain-class for we simply type
# create-domain-class worklog.User

Now, we need to add some properties to the user, a unique field called email of type String.

String email

So to check that we have a running application, we create some views and run our app locally to see what we have:

# generate-all worklog.User
# run-app 
(notice that you get autocompletion by pressing "tab" in interactive-mode)

The app should now be running on localhost:8080/worklog :
Voila, the app is running.


Now we get down to business. I need authentication! Luckily there are some grails-plugins for that, lets see... I kind of like the sound of the oauth-plugin, so I think I will try that. Installation: always install it by adding it to the BuildConfig-file(as opposed to installing it command-line-style). That way it´s easy to keep track of what you have installed, and upgrade will be less painful. At the time, the version is 1.0, so I add this to my BuildConfig in the plugin-section (current version is 2.0.1, check if it has been updated):

    compile ':oauth:2.0.1'
Thats it? Nope. We need to configure it to authenticate with google. In my Config.groovy, I need to add


oauth {
    providers {
        google {
            api = GoogleApi
            key = '1057869129521.apps.googleusercontent.com'
            secret = 'zaOsvnGrxyZ0kRciJJew0xbb'
            successUri = '/authenticate/success'
            failureUri = '/authenticate/failure'
            scope = 'https://www.googleapis.com/auth/userinfo.email'
            callback = "${grails.serverURL}/oauth/callback"
        }
    }
}



Now,  replace the key and with some sane value and same for the secret (my settings wont work well for you, and will change in a bit). Obtain this from google (go to the apis console link). Of course, now we need to create the success and failure uris...

# create-controller worklog.auth.Authenticate
Wow. Ok, lets see if we can poke around with this. In the index.gsp, we add some code:

<oauth:connect provider="google">Log in with google</oauth:connect>
And in our Authenticate-controller, we add a service and a method for the "authenticate/success"
OauthService oauthService 
 
def success() { 
    Token googleAccessToken = session[oauthService.findSessionKeyForAccessToken('google')] 
    def userInfo = oauthService.getGoogleResource(googleAccessToken, 'https://www.googleapis.com/oauth2/v1/userinfo') 
    def mail = JSON.parse(userInfo.body) 
    render "Authenticated as $mail" 
}
Test and check, heres my result;


This concludes the goal of this session, next time I will work more on domain-objects and setting up some test-data (users) for the app.