diff options
author | Petteri Räty <betelgeuse@gentoo.org> | 2009-12-27 17:13:16 +0200 |
---|---|---|
committer | Petteri Räty <betelgeuse@gentoo.org> | 2009-12-27 17:17:41 +0200 |
commit | aa81c75596edc8bfbd625ada6c6a6c387492ce5c (patch) | |
tree | df74cae55a66779a71fa3368a4bf7707af48fab9 | |
parent | Generate rspec infrastructure (diff) | |
download | council-webapp-aa81c75596edc8bfbd625ada6c6a6c387492ce5c.tar.gz council-webapp-aa81c75596edc8bfbd625ada6c6a6c387492ce5c.tar.bz2 council-webapp-aa81c75596edc8bfbd625ada6c6a6c387492ce5c.zip |
Add initial functionality
Add initial functionality. Now there's the possibility to create
questions and vote on them.
-rw-r--r-- | .gems | 1 | ||||
-rw-r--r-- | app/controllers/questions_controller.rb | 7 | ||||
-rw-r--r-- | app/controllers/votes_controller.rb | 8 | ||||
-rw-r--r-- | app/models/question.rb | 35 | ||||
-rw-r--r-- | app/models/vote.rb | 35 | ||||
-rw-r--r-- | app/viewhints/question_hints.rb | 7 | ||||
-rw-r--r-- | app/views/front/index.dryml | 5 | ||||
-rw-r--r-- | app/views/taglibs/application.dryml | 2 | ||||
-rw-r--r-- | app/views/taglibs/auto/rapid/cards.dryml | 35 | ||||
-rw-r--r-- | app/views/taglibs/auto/rapid/forms.dryml | 59 | ||||
-rw-r--r-- | app/views/taglibs/auto/rapid/pages.dryml | 501 | ||||
-rw-r--r-- | config/initializers/hobo.rb | 1 | ||||
-rw-r--r-- | db/migrate/20091227115558_initial_schema.rb | 42 | ||||
-rw-r--r-- | db/migrate/20091227122303_hobo_migration_1.rb | 13 | ||||
-rw-r--r-- | db/schema.rb | 52 |
15 files changed, 797 insertions, 6 deletions
@@ -0,0 +1 @@ +hobo diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb new file mode 100644 index 0000000..77ff9fb --- /dev/null +++ b/app/controllers/questions_controller.rb @@ -0,0 +1,7 @@ +class QuestionsController < ApplicationController + + hobo_model_controller + + auto_actions :all + +end diff --git a/app/controllers/votes_controller.rb b/app/controllers/votes_controller.rb new file mode 100644 index 0000000..fa8fe6c --- /dev/null +++ b/app/controllers/votes_controller.rb @@ -0,0 +1,8 @@ +class VotesController < ApplicationController + + hobo_model_controller + + auto_actions :show + auto_actions_for :question, [:index,:new,:create] + +end diff --git a/app/models/question.rb b/app/models/question.rb new file mode 100644 index 0000000..dda0226 --- /dev/null +++ b/app/models/question.rb @@ -0,0 +1,35 @@ +class Question < ActiveRecord::Base + + hobo_model # Don't put anything above this + + fields do + name :string + question :text + timestamps + end + + belongs_to :creator, :class_name => "User", :creator => true + attr_readonly :creator + never_show :creator + has_many :votes + + # --- Permissions --- # + + def create_permitted? + acting_user.signed_up? + end + + def update_permitted? + acting_user.administrator? + false + end + + def destroy_permitted? + acting_user.administrator? + end + + def view_permitted?(field) + true + end + +end diff --git a/app/models/vote.rb b/app/models/vote.rb new file mode 100644 index 0000000..ce1b72d --- /dev/null +++ b/app/models/vote.rb @@ -0,0 +1,35 @@ +class Vote < ActiveRecord::Base + + hobo_model # Don't put anything above this + + fields do + support :boolean + reasoning :text + timestamps + end + + belongs_to :user, :creator => true + belongs_to :question + validates_presence_of :user, :question + never_show :user + + # --- Permissions --- # + + def create_permitted? + acting_user.signed_up? + end + + def update_permitted? + return false if user_changed? + acting_user.administrator? + end + + def destroy_permitted? + acting_user.administrator? + end + + def view_permitted?(field) + true + end + +end diff --git a/app/viewhints/question_hints.rb b/app/viewhints/question_hints.rb new file mode 100644 index 0000000..96d3008 --- /dev/null +++ b/app/viewhints/question_hints.rb @@ -0,0 +1,7 @@ +class QuestionHints < Hobo::ViewHints + + # model_name "My Model" + # field_names :field1 => "First Field", :field2 => "Second Field" + # field_help :field1 => "Enter what you want in this field" + children :votes +end diff --git a/app/views/front/index.dryml b/app/views/front/index.dryml index eab8d63..45bc6a1 100644 --- a/app/views/front/index.dryml +++ b/app/views/front/index.dryml @@ -6,10 +6,6 @@ <header class="content-header"> <h1>Welcome to <app-name/></h1> <section class="welcome-message"> - <h3>Congratulations! Your Hobo Rails App is up and running</h3> - <ul> - <li>To customise this page: edit app/views/front/index.dryml</li> - </ul> <% if User.count == 0 -%> <h3 style="margin-top: 20px;">There are no user accounts - please provide the details of the site administrator</h3> @@ -17,7 +13,6 @@ <signup-form/> </do> <% end -%> - </section> </header> diff --git a/app/views/taglibs/application.dryml b/app/views/taglibs/application.dryml index 4f40412..198ec95 100644 --- a/app/views/taglibs/application.dryml +++ b/app/views/taglibs/application.dryml @@ -6,4 +6,4 @@ <set-theme name="clean"/> -<def tag="app-name">Gentoocouncil</def> +<def tag="app-name">Gentoo Council</def> diff --git a/app/views/taglibs/auto/rapid/cards.dryml b/app/views/taglibs/auto/rapid/cards.dryml new file mode 100644 index 0000000..38c8c7f --- /dev/null +++ b/app/views/taglibs/auto/rapid/cards.dryml @@ -0,0 +1,35 @@ +<!-- AUTOMATICALLY GENERATED FILE - DO NOT EDIT --> + +<def tag="card" for="Question"> + <card class="question" param="default" merge> + <header: param> + <h4 param="heading"><a><name/></a></h4> + </header:> + <body: param> + <a:creator param="creator-link"/> + <ht key="votes.collection.count" count="&this.votes.size"> + <count:votes param/> + </ht> + </body:> + </card> +</def> + +<def tag="card" for="User"> + <card class="user" param="default" merge> + <header: param> + <h4 param="heading"><a><name/></a></h4> + </header:> + </card> +</def> + +<def tag="card" for="Vote"> + <card class="vote" param="default" merge> + <header: param> + <h4 param="heading"><a><name/></a></h4> + </header:> + <body: param> + <a:user param="creator-link"/> + </body:> + </card> +</def> + diff --git a/app/views/taglibs/auto/rapid/forms.dryml b/app/views/taglibs/auto/rapid/forms.dryml new file mode 100644 index 0000000..37eb449 --- /dev/null +++ b/app/views/taglibs/auto/rapid/forms.dryml @@ -0,0 +1,59 @@ +<!-- AUTOMATICALLY GENERATED FILE - DO NOT EDIT --> + +<def tag="form" for="Question"> + <form merge param="default"> + <error-messages param/> + <field-list fields="name, question" param/> + <div param="actions"> + <submit label="#{ht 'questions.actions.save', :default=>['Save']}" param/><or-cancel param="cancel"/> + </div> + </form> +</def> + + + +<def tag="form" for="User"> + <form merge param="default"> + <error-messages param/> + <field-list fields="name, email_address, administrator, state" param/> + <div param="actions"> + <submit label="#{ht 'users.actions.save', :default=>['Save']}" param/><or-cancel param="cancel"/> + </div> + </form> +</def> + +<def tag="signup-form" polymorphic/> +<def tag="signup-form" for="User"> + <form lifecycle="signup" merge param="default"> + <error-messages param/> + <field-list fields="name, email_address, password, password_confirmation" param/> + <div param="actions"> + <submit label="#{ht 'users.actions.signup', :default=>['Signup']}" param/><or-cancel param="cancel"/> + </div> + </form> +</def> + +<def tag="reset-password-form" polymorphic/> +<def tag="reset-password-form" for="User"> + <form lifecycle="reset_password" merge param="default"> + <error-messages param/> + <input type="hidden" name="key" value="&this.lifecycle.provided_key" if="&this.lifecycle.provided_key"/> + <field-list fields="password, password_confirmation" param/> + <div param="actions"> + <submit label="#{ht 'users.actions.reset_password', :default=>['Reset Password']}" param/><or-cancel param="cancel"/> + </div> + </form> +</def> + +<def tag="form" for="Vote"> + <form merge param="default"> + <error-messages param/> + <field-list fields="support, reasoning, question" param/> + <div param="actions"> + <submit label="#{ht 'votes.actions.save', :default=>['Save']}" param/><or-cancel param="cancel"/> + </div> + </form> +</def> + + + diff --git a/app/views/taglibs/auto/rapid/pages.dryml b/app/views/taglibs/auto/rapid/pages.dryml new file mode 100644 index 0000000..7fa4f48 --- /dev/null +++ b/app/views/taglibs/auto/rapid/pages.dryml @@ -0,0 +1,501 @@ +<!-- AUTOMATICALLY GENERATED FILE - DO NOT EDIT --> + +<!-- ====== Main Navigation ====== --> + +<def tag="main-nav"> + <navigation class="main-nav" merge-attrs param="default"> + <nav-item href="#{base_url}/">Home</nav-item> + <nav-item with="&Question"><ht key="questions.nav_item">Questions</ht></nav-item> + </navigation> +</def> + + + + +<!-- ====== Question Pages ====== --> + +<def tag="index-page" for="Question"> + <page merge title="#{ht 'questions.index.title', :default=>['Questions'] }"> + <body: class="index-page question" param/> + + <content: param> + <header param="content-header"> + <h2 param="heading"> + <ht key="questions.index.heading"> + Questions + </ht> + </h2> + + <p param="count" if> + <ht key="questions.collection.count" count="&this.size"> + There <count prefix="are"/> + </ht> + </p> + </header> + + <section param="content-body"> + <a action="new" to="&model" param="new-link"> + <ht key="questions.actions.new">New Question</ht> + </a> + + <page-nav param="top-page-nav"/> + + <collection param/> + + <page-nav param="bottom-page-nav"/> + + + </section> + </content:> + </page> +</def> + + +<def tag="new-page" for="Question"> + <page merge title="#{ht 'questions.new.title', :default=>['New Question'] }"> + <body: class="new-page question" param/> + + <content: param> + <section param="content-header"> + <h2 param="heading"> + <ht key="questions.new.heading"> + New Question + </ht> + </h2> + </section> + + <section param="content-body"> + <form param> + <submit: label="#{ht 'questions.actions.create', :default=>['Create Question']}"/> + </form> + </section> + </content:> + </page> +</def> + + +<def tag="show-page" for="Question"> + <page merge title="#{ht 'questions.show.title', :default=>['Question'] }"> + + <body: class="show-page question" param/> + + <content: param> + <header param="content-header"> + <h2 param="heading"> + <ht key="questions.show.heading" name="&this.respond_to?(:name) ? this.name : ''"> + <name/> + </ht> + </h2> + + <record-flags fields="" param/> + + <a:creator param="creator-link"/> + + <a action="edit" if="&can_edit?" param="edit-link"> + <ht key="questions.actions.edit" name="&this.respond_to?(:name) ? this.name : ''"> + Edit Question + </ht> + </a> + </header> + + <section param="content-body"> + <field-list fields="question" param/> + <section param="collection-section"> + <h3 param="collection-heading"> + <ht key="questions.collection.heading.other" > + Votes + </ht> + </h3> + + <collection:votes param/> + + <a:votes action="new" if="&can_create?(@question.votes)" param="new-link"> + <ht key="votes.actions.new"> + New Vote + </ht> + </a:votes> + </section> + </section> + </content:> + + </page> +</def> + + +<def tag="edit-page" for="Question"> + <page merge title="#{ht 'questions.edit.title', :default=>['Edit Question'] }"> + + <body: class="edit-page question" param/> + + <content:> + <section param="content-header"> + <h2 param="heading"> + <ht key="questions.edit.heading" name="&this.respond_to?(:name) ? this.name : ''"> + Edit <type-name/> + </ht> + </h2> + <delete-button label="#{ht 'questions.actions.delete', :default=>['Remove This Question']}" param/> + </section> + + <section param="content-body"> + <form param/> + </section> + </content:> + + </page> +</def> + + + + + +<!-- ====== User Pages ====== --> + +<def tag="index-page" for="User"> + <page merge title="#{ht 'users.index.title', :default=>['Users'] }"> + <body: class="index-page user" param/> + + <content: param> + <header param="content-header"> + <h2 param="heading"> + <ht key="users.index.heading"> + Users + </ht> + </h2> + + <p param="count" if> + <ht key="users.collection.count" count="&this.size"> + There <count prefix="are"/> + </ht> + </p> + </header> + + <section param="content-body"> + + <page-nav param="top-page-nav"/> + + <collection param/> + + <page-nav param="bottom-page-nav"/> + + + </section> + </content:> + </page> +</def> + + +<def tag="new-page" for="User"> + <page merge title="#{ht 'users.new.title', :default=>['New User'] }"> + <body: class="new-page user" param/> + + <content: param> + <section param="content-header"> + <h2 param="heading"> + <ht key="users.new.heading"> + New User + </ht> + </h2> + </section> + + <section param="content-body"> + <form param> + <submit: label="#{ht 'users.actions.create', :default=>['Create User']}"/> + </form> + </section> + </content:> + </page> +</def> + + +<def tag="show-page" for="User"> + <page merge title="#{ht 'users.show.title', :default=>['User'] }"> + + <body: class="show-page user" param/> + + <content: param> + <header param="content-header"> + <h2 param="heading"> + <ht key="users.show.heading" name="&this.respond_to?(:name) ? this.name : ''"> + <name/> + </ht> + </h2> + + <record-flags fields="administrator" param/> + + <a action="edit" if="&can_edit?" param="edit-link"> + <ht key="users.actions.edit" name="&this.respond_to?(:name) ? this.name : ''"> + Edit User + </ht> + </a> + </header> + + <section param="content-body"> + <field-list fields="email_address, state" param/> + </section> + </content:> + + </page> +</def> + + +<def tag="edit-page" for="User"> + <page merge title="#{ht 'users.edit.title', :default=>['Edit User'] }"> + + <body: class="edit-page user" param/> + + <content:> + <section param="content-header"> + <h2 param="heading"> + <ht key="users.edit.heading" name="&this.respond_to?(:name) ? this.name : ''"> + Edit <type-name/> + </ht> + </h2> + <delete-button label="#{ht 'users.actions.delete', :default=>['Remove This User']}" param/> + </section> + + <section param="content-body"> + <form param/> + </section> + </content:> + + </page> +</def> + + +<def tag="signup-page" polymorphic/> +<def tag="signup-page" for="User"> + + <page title="#{ht 'users.signup.title', :default=>['Signup']}" merge> + + <body: class="lifecycle-start-page signup-page" param/> + + <content: param> + <header param="content-header"> + <h2 param="heading"> + <ht key="users.signup.heading"> + Signup + </ht> + </h2> + </header> + + <section param="content-body"> + <signup-form param="form"/> + </section> + </content:> + + </page> +</def> + +<def tag="reset-password-page" polymorphic/> +<def tag="reset-password-page" for="User"> + <page title="#{ht 'users.reset_password.title', :default=>['Reset Password']}" merge> + + <body: class="lifecycle-transition-page reset-password-page" param/> + + <content:> + <header param="content-header"> + <h2 param="heading"> + <ht key="users.reset_password.heading"> + Reset Password + </ht> + </h2> + </header> + + <section param="content-body"> + <reset-password-form param="form"/> + </section> + </content:> + + </page> +</def> + + + +<!-- ====== Vote Pages ====== --> + +<def tag="index-page" for="Vote"> + <page merge title="#{ht 'votes.index.title', :default=>['Votes'] }"> + <body: class="index-page vote" param/> + + <content: param> + <header param="content-header"> + <h2 param="heading"> + <ht key="votes.index.heading"> + Votes + </ht> + </h2> + + <p param="count" if> + <ht key="votes.collection.count" count="&this.size"> + There <count prefix="are"/> + </ht> + </p> + </header> + + <section param="content-body"> + + <page-nav param="top-page-nav"/> + + <collection param/> + + <page-nav param="bottom-page-nav"/> + + + </section> + </content:> + </page> +</def> + + +<def tag="new-page" for="Vote"> + <page merge title="#{ht 'votes.new.title', :default=>['New Vote'] }"> + <body: class="new-page vote" param/> + + <content: param> + <section param="content-header"> + <h2 param="heading"> + <ht key="votes.new.heading"> + New Vote + </ht> + </h2> + </section> + + <section param="content-body"> + <form param> + <submit: label="#{ht 'votes.actions.create', :default=>['Create Vote']}"/> + </form> + </section> + </content:> + </page> +</def> + + +<def tag="show-page" for="Vote"> + <page merge title="#{ht 'votes.show.title', :default=>['Vote'] }"> + + <body: class="show-page vote" param/> + + <content: param> + <header param="content-header"> + <a:question param="parent-link">« <ht key="votes.actions.back" to="question"><name/></ht></a:question> + <h2 param="heading"> + <ht key="votes.show.heading" name="&this.respond_to?(:name) ? this.name : ''"> + <name/> + </ht> + </h2> + + <record-flags fields="support" param/> + + <a:user param="creator-link"/> + </header> + + <section param="content-body"> + <field-list fields="reasoning" param/> + </section> + </content:> + + </page> +</def> + + +<def tag="edit-page" for="Vote"> + <page merge title="#{ht 'votes.edit.title', :default=>['Edit Vote'] }"> + + <body: class="edit-page vote" param/> + + <content:> + <section param="content-header"> + <h2 param="heading"> + <ht key="votes.edit.heading" name="&this.respond_to?(:name) ? this.name : ''"> + Edit <type-name/> + </ht> + </h2> + <delete-button label="#{ht 'votes.actions.delete', :default=>['Remove This Vote']}" param/> + </section> + + <section param="content-body"> + <form param/> + </section> + </content:> + + </page> +</def> + +<def tag="index-for-question-page" polymorphic/> +<def tag="index-for-question-page" for="Vote"> + <page merge title="#{ht 'votes.index_for_owner.title', :default=>['Votes for']} #{name :with => @question, :no_wrapper => true}"> + <body: class="index-for-owner-page question vote" param/> + <content: param> + <header param="content-header"> + <div param="back-to"> + <ht key="hobo.actions.back">Back to</ht> <a with="&@question"/> + </div> + <h2 param="heading"> + <ht key="votes.index_for_owner.heading.other"> + Votes + </ht> + </h2> + <h3 param="subheading"> + <ht key="votes.index_for_owner.subheading"> + For: + </ht> + <a with="&@question"/> + </h3> + <p param="count" if> + <ht key="votes.collection.count" count="&this.size"> + There <count prefix="are"/> + </ht> + </p> + </header> + + <section param="content-body"> + <a action="new" to="&model" param="new-link"> + <ht key="votes.actions.new" >New Vote</ht> + </a> + + + <page-nav param="top-page-nav"/> + + <collection param/> + + <page-nav param="bottom-page-nav"/> + </section> + </content:> + </page> +</def> + + +<def tag="new-for-question-page" polymorphic/> +<def tag="new-for-question-page" for="Vote"> + <page merge title="#{ht 'votes.new_for_owner.title', :default=>['New Vote for']} #{name :with => @question}"> + <body: class="new-for-owner-page vote" param/> + + <content: param> + <header param="content-header"> + <h2 param="heading"> + <ht key="votes.new_for_owner.heading"> + New Vote + </ht> + </h2> + <h3 param="subheading"> + <ht key="votes.new_for_owner.subheading"> + For: + </ht> + <a with="&@question"/> + </h3> + </header> + + <section param="content-body"> + <form owner="question" method="post" param> + <field-list: skip="question"/> + <submit: label="#{ht 'votes.actions.create', :default=>['Create Vote']}"/> + </form> + </section> + </content:> + </page> +</def> + + + + diff --git a/config/initializers/hobo.rb b/config/initializers/hobo.rb index 286b2a6..164cd22 100644 --- a/config/initializers/hobo.rb +++ b/config/initializers/hobo.rb @@ -1 +1,2 @@ Hobo::ModelRouter.reload_routes_on_every_request = true +Hobo::Dryml.precompile_taglibs if File.basename($0) != "rake" && Rails.env.production? diff --git a/db/migrate/20091227115558_initial_schema.rb b/db/migrate/20091227115558_initial_schema.rb new file mode 100644 index 0000000..dc9c8d1 --- /dev/null +++ b/db/migrate/20091227115558_initial_schema.rb @@ -0,0 +1,42 @@ +class InitialSchema < ActiveRecord::Migration + def self.up + create_table :votes do |t| + t.boolean :support + t.text :reasoning + t.datetime :created_at + t.datetime :updated_at + t.integer :user_id + end + add_index :votes, [:user_id] + + create_table :questions do |t| + t.string :name + t.text :question + t.datetime :created_at + t.datetime :updated_at + t.integer :creator_id + end + add_index :questions, [:creator_id] + + create_table :users do |t| + t.string :crypted_password, :limit => 40 + t.string :salt, :limit => 40 + t.string :remember_token + t.datetime :remember_token_expires_at + t.string :name + t.string :email_address + t.boolean :administrator, :default => false + t.datetime :created_at + t.datetime :updated_at + t.string :state, :default => "active" + t.datetime :key_timestamp + end + add_index :users, [:state] + end + + def self.down + drop_table :votes + drop_table :questions + drop_table :users + end +end diff --git a/db/migrate/20091227122303_hobo_migration_1.rb b/db/migrate/20091227122303_hobo_migration_1.rb new file mode 100644 index 0000000..81e3ff2 --- /dev/null +++ b/db/migrate/20091227122303_hobo_migration_1.rb @@ -0,0 +1,13 @@ +class HoboMigration1 < ActiveRecord::Migration + def self.up + add_column :votes, :question_id, :integer + + add_index :votes, [:question_id] + end + + def self.down + remove_column :votes, :question_id + + remove_index :votes, :name => :index_votes_on_question_id + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..708d019 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,52 @@ +# This file is auto-generated from the current state of the database. Instead of editing this file, +# please use the migrations feature of Active Record to incrementally modify your database, and +# then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your database schema. If you need +# to create the application database on another system, you should be using db:schema:load, not running +# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20091227122303) do + + create_table "questions", :force => true do |t| + t.string "name" + t.text "question" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "creator_id" + end + + add_index "questions", ["creator_id"], :name => "index_questions_on_creator_id" + + create_table "users", :force => true do |t| + t.string "crypted_password", :limit => 40 + t.string "salt", :limit => 40 + t.string "remember_token" + t.datetime "remember_token_expires_at" + t.string "name" + t.string "email_address" + t.boolean "administrator", :default => false + t.datetime "created_at" + t.datetime "updated_at" + t.string "state", :default => "active" + t.datetime "key_timestamp" + end + + add_index "users", ["state"], :name => "index_users_on_state" + + create_table "votes", :force => true do |t| + t.boolean "support" + t.text "reasoning" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "user_id" + t.integer "question_id" + end + + add_index "votes", ["question_id"], :name => "index_votes_on_question_id" + add_index "votes", ["user_id"], :name => "index_votes_on_user_id" + +end |