mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-16 07:10:12 +01:00
Initial import
git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@1 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
commit
ec3ee77797
83 changed files with 3361 additions and 0 deletions
13
tracks/README_FIRST.txt
Normal file
13
tracks/README_FIRST.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
The main README.txt file is in tracks/doc/README.txt, and the change log in tracks/doc/CHANGENOTES.txt.
|
||||
|
||||
The database structure dump file (with some test contents) is in tracks/db/tracks_dump 03.01.2005.sql, which you can import into your database.
|
||||
|
||||
** IMPORTANT **
|
||||
|
||||
Before you do anything else, you need to copy certain files and rename the copy:
|
||||
|
||||
tracks/config/database.yml.tmpl -> tracks/config/database.yml
|
||||
tracks/config/settings.yml.tmpl -> tracks/config/settings.yml
|
||||
tracks/log.tmpl -> tracks/log
|
||||
|
||||
You need to put your settings into database.yml and settings.yml. Just leave the .tmpl versions as they are. I'm sorry to impose this extra step, but it's important for the subversion repository not to have your super-seekrit MySQL database user name and password checked in to the repository for all to see!
|
||||
29
tracks/README_LOGIN
Normal file
29
tracks/README_LOGIN
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
== Installation
|
||||
|
||||
Done generating the login system. but there are still a few things you have to do
|
||||
manually. First open your application.rb and add
|
||||
|
||||
require_dependency "login_system"
|
||||
|
||||
to the top of the file and include the login system with
|
||||
|
||||
include LoginSystem
|
||||
|
||||
The beginning of your ApplicationController.
|
||||
It should look something like this :
|
||||
|
||||
require_dependency "login_system"
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
include LoginSystem
|
||||
|
||||
|
||||
After you have done the modifications the the AbstractController you can
|
||||
import the user model into the database. This model is meant as an example
|
||||
and you should extend it. If you just want to get things up and running you
|
||||
can find some create table syntax in db/user_model.sql.
|
||||
|
||||
== Useage
|
||||
|
||||
Now you can go around and happily add "before_filter :login_required" to the controllers which you would like to protect.
|
||||
If the user hits a controller with the login_required filter he will be redirected to the login page and redirected back after a successful login. You can find the login_system.rb in the lib/ directory. It comes with some comments which should help explain the general useage.
|
||||
112
tracks/Rakefile
Normal file
112
tracks/Rakefile
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
$VERBOSE = nil
|
||||
|
||||
require File.dirname(__FILE__) + '/config/environment'
|
||||
require 'code_statistics'
|
||||
|
||||
desc "Run all the tests on a fresh test database"
|
||||
task :default => [ :clone_development_structure_to_test, :test_units, :test_functional ]
|
||||
|
||||
desc "Generate API documentatio, show coding stats"
|
||||
task :doc => [ :appdoc, :stats ]
|
||||
|
||||
|
||||
desc "Run the unit tests in test/unit"
|
||||
Rake::TestTask.new("test_units") { |t|
|
||||
t.libs << "test"
|
||||
t.pattern = 'test/unit/*_test.rb'
|
||||
t.verbose = true
|
||||
}
|
||||
|
||||
desc "Run the functional tests in test/functional"
|
||||
Rake::TestTask.new("test_functional") { |t|
|
||||
t.libs << "test"
|
||||
t.pattern = 'test/functional/*_test.rb'
|
||||
t.verbose = true
|
||||
}
|
||||
|
||||
desc "Generate documentation for the application"
|
||||
Rake::RDocTask.new("appdoc") { |rdoc|
|
||||
rdoc.rdoc_dir = 'doc/app'
|
||||
rdoc.title = "Rails Application Documentation"
|
||||
rdoc.options << '--line-numbers --inline-source'
|
||||
rdoc.rdoc_files.include('doc/README_FOR_APP')
|
||||
rdoc.rdoc_files.include('app/**/*.rb')
|
||||
}
|
||||
|
||||
desc "Generate documentation for the Rails framework"
|
||||
Rake::RDocTask.new("apidoc") { |rdoc|
|
||||
rdoc.rdoc_dir = 'doc/api'
|
||||
rdoc.title = "Rails Framework Documentation"
|
||||
rdoc.options << '--line-numbers --inline-source'
|
||||
rdoc.rdoc_files.include('README')
|
||||
rdoc.rdoc_files.include('CHANGELOG')
|
||||
rdoc.rdoc_files.include('vendor/railties/lib/breakpoint.rb')
|
||||
rdoc.rdoc_files.include('vendor/railties/CHANGELOG')
|
||||
rdoc.rdoc_files.include('vendor/railties/MIT-LICENSE')
|
||||
rdoc.rdoc_files.include('vendor/activerecord/README')
|
||||
rdoc.rdoc_files.include('vendor/activerecord/CHANGELOG')
|
||||
rdoc.rdoc_files.include('vendor/activerecord/lib/active_record/**/*.rb')
|
||||
rdoc.rdoc_files.exclude('vendor/activerecord/lib/active_record/vendor/*')
|
||||
rdoc.rdoc_files.include('vendor/actionpack/README')
|
||||
rdoc.rdoc_files.include('vendor/actionpack/CHANGELOG')
|
||||
rdoc.rdoc_files.include('vendor/actionpack/lib/action_controller/**/*.rb')
|
||||
rdoc.rdoc_files.include('vendor/actionpack/lib/action_view/**/*.rb')
|
||||
rdoc.rdoc_files.include('vendor/actionmailer/README')
|
||||
rdoc.rdoc_files.include('vendor/actionmailer/CHANGELOG')
|
||||
rdoc.rdoc_files.include('vendor/actionmailer/lib/action_mailer/base.rb')
|
||||
}
|
||||
|
||||
desc "Report code statistics (KLOCs, etc) from the application"
|
||||
task :stats do
|
||||
CodeStatistics.new(
|
||||
["Helpers", "app/helpers"],
|
||||
["Controllers", "app/controllers"],
|
||||
["Functionals", "test/functional"],
|
||||
["Models", "app/models"],
|
||||
["Units", "test/unit"]
|
||||
).to_s
|
||||
end
|
||||
|
||||
desc "Recreate the test databases from the development structure"
|
||||
task :clone_development_structure_to_test => [ :db_structure_dump, :purge_test_database ] do
|
||||
if ActiveRecord::Base.configurations["test"]["adapter"] == "mysql"
|
||||
ActiveRecord::Base.establish_connection(:test)
|
||||
ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
|
||||
IO.readlines("db/development_structure.sql").join.split("\n\n").each do |table|
|
||||
ActiveRecord::Base.connection.execute(table)
|
||||
end
|
||||
elsif ActiveRecord::Base.configurations["test"]["adapter"] == "postgresql"
|
||||
`psql -U #{ActiveRecord::Base.configurations["test"]["username"]} -f db/development_structure.sql #{ActiveRecord::Base.configurations["test"]["database"]}`
|
||||
elsif ActiveRecord::Base.configurations["test"]["adapter"] == "sqlite"
|
||||
`sqlite #{ActiveRecord::Base.configurations["test"]["dbfile"]} < db/development_structure.sql`
|
||||
end
|
||||
end
|
||||
|
||||
desc "Dump the database structure to a SQL file"
|
||||
task :db_structure_dump do
|
||||
if ActiveRecord::Base.configurations["development"]["adapter"] == "mysql"
|
||||
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations["development"])
|
||||
File.open("db/development_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
|
||||
elsif ActiveRecord::Base.configurations["development"]["adapter"] == "postgresql"
|
||||
`pg_dump -U #{ActiveRecord::Base.configurations["development"]["username"]} -s -f db/development_structure.sql #{ActiveRecord::Base.configurations["development"]["database"]}`
|
||||
elsif ActiveRecord::Base.configurations["development"]["adapter"] == "sqlite"
|
||||
`sqlite #{ActiveRecord::Base.configurations["development"]["dbfile"]} .schema > db/development_structure.sql`
|
||||
end
|
||||
end
|
||||
|
||||
desc "Drop the test database and bring it back again"
|
||||
task :purge_test_database do
|
||||
if ActiveRecord::Base.configurations["test"]["adapter"] == "mysql"
|
||||
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations["development"])
|
||||
ActiveRecord::Base.connection.recreate_database(ActiveRecord::Base.configurations["test"]["database"])
|
||||
elsif ActiveRecord::Base.configurations["test"]["adapter"] == "postgresql"
|
||||
`dropdb -U #{ActiveRecord::Base.configurations["test"]["username"]} #{ActiveRecord::Base.configurations["test"]["database"]}`
|
||||
`createdb -U #{ActiveRecord::Base.configurations["test"]["username"]} #{ActiveRecord::Base.configurations["test"]["database"]}`
|
||||
elsif ActiveRecord::Base.configurations["test"]["adapter"] == "sqlite"
|
||||
File.delete(ActiveRecord::Base.configurations["test"]["dbfile"]) if File.exist?(ActiveRecord::Base.configurations["test"]["dbfile"])
|
||||
end
|
||||
end
|
||||
18
tracks/app/controllers/application.rb
Normal file
18
tracks/app/controllers/application.rb
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# The filters added to this controller will be run for all controllers in the application.
|
||||
# Likewise will all the methods added be available for all controllers.
|
||||
|
||||
require_dependency "login_system"
|
||||
require_dependency "redcloth"
|
||||
require 'date'
|
||||
|
||||
$delete_img = "<img src=\"/images/delete.png\" width=\"10\" height=\"10\" />"
|
||||
$edit_img = "<img src=\"/images/edit.png\" width=\"10\" height=\"10\" />"
|
||||
$notes_img = "<img src=\"/images/notes.png\" width=\"10\" height=\"10\" />"
|
||||
$done_img = "<img src=\"/images/done.png\" width=\"16\" height=\"16\" />"
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
|
||||
helper :application
|
||||
include LoginSystem
|
||||
|
||||
end
|
||||
94
tracks/app/controllers/context_controller.rb
Normal file
94
tracks/app/controllers/context_controller.rb
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
class ContextController < ApplicationController
|
||||
|
||||
|
||||
helper :context
|
||||
model :project
|
||||
scaffold :context
|
||||
before_filter :login_required
|
||||
|
||||
layout "standard"
|
||||
|
||||
|
||||
# Main method for listing contexts
|
||||
# Set page title, and collect existing contexts in @contexts
|
||||
#
|
||||
def list
|
||||
@page_title = "List Contexts"
|
||||
@contexts = Context.find_all
|
||||
end
|
||||
|
||||
|
||||
# Called by a form button
|
||||
# Parameters from form fields should be passed to create new context
|
||||
#
|
||||
def add_context
|
||||
context = Context.new
|
||||
context.name = @params["new_context"]["name"]
|
||||
|
||||
if context.save
|
||||
flash["confirmation"] = "Succesfully created context"
|
||||
redirect_to( :action => "list" )
|
||||
else
|
||||
flash["warning"] = "Couldn't add new context"
|
||||
redirect_to( :action => "list" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Filter the contexts to show just the one passed in the URL
|
||||
# e.g. <home>/context/show/<context_id> shows just <context_id>.
|
||||
#
|
||||
def show
|
||||
@context = Context.find(@params["id"])
|
||||
@places = Context.find_all
|
||||
@projects = Project.find_all
|
||||
@page_title = "Context: #{@context.name.capitalize}"
|
||||
@not_done = Todo.find_all( "context_id=#{@context.id} AND done=0", "created DESC" )
|
||||
end
|
||||
|
||||
|
||||
# Called by a form button
|
||||
# Parameters from form fields are passed to create new action
|
||||
# in the selected context.
|
||||
def add_item
|
||||
item = Todo.new
|
||||
item.attributes = @params["new_item"]
|
||||
|
||||
# Convert the date format entered (as set in config/settings.yml)
|
||||
# to the mysql format YYYY-MM-DD
|
||||
if @params["new_item"]["due"] != ""
|
||||
date_fmt = app_configurations["formats"]["date"]
|
||||
formatted_date = DateTime.strptime(@params["new_item"]["due"], "#{date_fmt}")
|
||||
item.due = formatted_date.strftime("%Y-%m-%d")
|
||||
else
|
||||
item.due = "0000-00-00"
|
||||
end
|
||||
|
||||
back_to = item.context_id
|
||||
|
||||
if item.save
|
||||
flash["confirmation"] = "Succesfully added action to context"
|
||||
redirect_to( :controller => "context", :action => "show", :id => "#{back_to}" )
|
||||
else
|
||||
flash["warning"] = "Could not add action to context"
|
||||
redirect_to( :controller => "context", :action => "show", :id => "#{back_to}" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Fairly self-explanatory; deletes the context
|
||||
# If the context contains actions, you'll get a warning dialogue.
|
||||
# If you choose to go ahead, any actions in the context will also be deleted.
|
||||
def destroy
|
||||
context = Context.find(@params['id'])
|
||||
if context.destroy
|
||||
flash["confirmation"] = "Succesfully deleted context"
|
||||
redirect_to( :action => "list" )
|
||||
else
|
||||
flash["warning"] = "Couldn't delete context"
|
||||
redirect_to( :action => "list" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
33
tracks/app/controllers/feed_controller.rb
Normal file
33
tracks/app/controllers/feed_controller.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Produces an feeds of the next actions, both RSS and plain text
|
||||
#
|
||||
class FeedController < ApplicationController
|
||||
|
||||
helper :feed
|
||||
model :todo, :context, :project
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
# Builds an RSS feed for the latest 15 items
|
||||
# This is fairly basic: it lists the action description as the title
|
||||
# and the item context as the description
|
||||
#
|
||||
def na_feed
|
||||
@not_done = Todo.find_all( "done=0", "created DESC" )
|
||||
@headers["Content-Type"] = "text/xml; charset=utf-8"
|
||||
end
|
||||
|
||||
# Builds a plain text page listing all the next actions,
|
||||
# sorted by context. Showing notes doesn' make much sense here
|
||||
# so they are omitted. You can use this with GeekTool to get your next actions
|
||||
# on the desktop:
|
||||
# curl http://url_for_the_app/feed/na_text
|
||||
#
|
||||
def na_text
|
||||
@places = Context.find_all
|
||||
@projects = Project.find_all
|
||||
@not_done = Todo.find_all( "done=0", "context_id ASC" )
|
||||
@headers["Content-Type"] = "text/plain; charset=utf-8"
|
||||
end
|
||||
|
||||
end
|
||||
49
tracks/app/controllers/login_controller.rb
Normal file
49
tracks/app/controllers/login_controller.rb
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
class LoginController < ApplicationController
|
||||
model :user
|
||||
layout 'scaffold'
|
||||
|
||||
def login
|
||||
case @request.method
|
||||
when :post
|
||||
if @session['user'] = User.authenticate(@params['user_login'], @params['user_password'])
|
||||
|
||||
flash['notice'] = "Login successful"
|
||||
redirect_back_or_default :controller => "todo", :action => "list"
|
||||
else
|
||||
@login = @params['user_login']
|
||||
@message = "Login unsuccessful"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def signup
|
||||
case @request.method
|
||||
when :post
|
||||
@user = User.new(@params['user'])
|
||||
|
||||
if @user.save
|
||||
@session['user'] = User.authenticate(@user.login, @params['user']['password'])
|
||||
flash['notice'] = "Signup successful"
|
||||
redirect_back_or_default :controller => "todo", :action => "list"
|
||||
end
|
||||
when :get
|
||||
@user = User.new
|
||||
end
|
||||
end
|
||||
|
||||
def delete
|
||||
if @params['id']
|
||||
@user = User.find(@params['id'])
|
||||
@user.destroy
|
||||
end
|
||||
redirect_back_or_default :controller => "todo", :action => "list"
|
||||
end
|
||||
|
||||
def logout
|
||||
@session['user'] = nil
|
||||
end
|
||||
|
||||
def welcome
|
||||
end
|
||||
|
||||
end
|
||||
107
tracks/app/controllers/project_controller.rb
Normal file
107
tracks/app/controllers/project_controller.rb
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
class ProjectController < ApplicationController
|
||||
|
||||
helper :project
|
||||
model :context
|
||||
model :todo
|
||||
scaffold :project
|
||||
|
||||
before_filter :login_required
|
||||
layout "standard"
|
||||
|
||||
# Main method for listing projects
|
||||
# Set page title, and collect existing projects in @projects
|
||||
#
|
||||
def list
|
||||
@page_title = "List Projects"
|
||||
@projects = Project.find_all
|
||||
end
|
||||
|
||||
|
||||
# Filter the projects to show just the one passed in the URL
|
||||
# e.g. <home>/project/show/<project_id> shows just <project_id>.
|
||||
#
|
||||
def show
|
||||
@project = Project.find(@params["id"])
|
||||
@places = Context.find_all
|
||||
@page_title = "Project: #{@project.name}"
|
||||
@not_done = Todo.find_all( "project_id=#{@project.id} AND done=0", "created DESC" )
|
||||
end
|
||||
|
||||
|
||||
# Called by a form button
|
||||
# Parameters from form fields should be passed to create new project
|
||||
#
|
||||
def add_project
|
||||
project = Project.new
|
||||
project.name = @params["new_project"]["name"]
|
||||
|
||||
if project.save
|
||||
flash["confirmation"] = "Succesfully added project"
|
||||
redirect_to( :action => "list" )
|
||||
else
|
||||
flash["warning"] = "Couldn't add project"
|
||||
redirect_to( :action => "list" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Called by a form button
|
||||
# Parameters from form fields should be passed to create new item
|
||||
#
|
||||
def add_item
|
||||
item = Todo.new
|
||||
item.attributes = @params["new_item"]
|
||||
|
||||
# Convert the date format entered (as set in config/settings.yml)
|
||||
# to the mysql format YYYY-MM-DD
|
||||
if @params["new_item"]["due"] != ""
|
||||
date_fmt = app_configurations["formats"]["date"]
|
||||
formatted_date = DateTime.strptime(@params["new_item"]["due"], "#{date_fmt}")
|
||||
item.due = formatted_date.strftime("%Y-%m-%d")
|
||||
else
|
||||
item.due = "0000-00-00"
|
||||
end
|
||||
|
||||
back_to = item.project_id
|
||||
|
||||
if item.save
|
||||
flash["confirmation"] = "Successfully added next action to project"
|
||||
redirect_to( :controller => "project", :action => "show", :id => "#{back_to}" )
|
||||
else
|
||||
flash["warning"] = "Couldn't add next action to project"
|
||||
redirect_to( :controller => "project", :action => "show", :id => "#{back_to}" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def destroy
|
||||
project = Project.find( @params['id'] )
|
||||
if project.destroy
|
||||
flash["confirmation"] = "Succesfully deleted project"
|
||||
redirect_to( :action => "list" )
|
||||
else
|
||||
flash["warning"] = "Couldn't delete project"
|
||||
redirect_to( :action => "list" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Toggles the 'done' status of the action
|
||||
def toggle_check
|
||||
item = Todo.find( @params['id'] )
|
||||
|
||||
case item.done
|
||||
when 0: item.done = 1; item.completed = Time.now()
|
||||
when 1: item.done = 0; item.completed = nil
|
||||
end
|
||||
|
||||
if item.save
|
||||
flash["confirmation"] = "Marked next action as completed"
|
||||
redirect_to( :action => "list" )
|
||||
else
|
||||
flash["warning"] = "Couldn't mark next action as completed"
|
||||
redirect_to( :action => "list" )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
111
tracks/app/controllers/todo_controller.rb
Normal file
111
tracks/app/controllers/todo_controller.rb
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
class TodoController < ApplicationController
|
||||
|
||||
helper :todo
|
||||
model :context
|
||||
model :project
|
||||
|
||||
scaffold :todo
|
||||
before_filter :login_required
|
||||
layout "standard"
|
||||
|
||||
# Main method for listing tasks
|
||||
# Set page title, and fill variables with contexts and done and not-done tasks
|
||||
#
|
||||
def list
|
||||
@page_title = "List tasks"
|
||||
@places = Context.find_all
|
||||
@projects = Project.find_all
|
||||
@not_done = Todo.find_all( "done=0", "completed DESC" )
|
||||
@done = Todo.find_all( "done=1", "completed DESC", 5 )
|
||||
end
|
||||
|
||||
|
||||
# List the completed tasks, sorted by completion date
|
||||
#
|
||||
def completed
|
||||
@page_title = "Completed tasks"
|
||||
@done = Todo.find_all( "done=1", "completed DESC" )
|
||||
end
|
||||
|
||||
|
||||
# Called by a form button
|
||||
# Parameters from form fields should be passed to create new item
|
||||
#
|
||||
def add_item
|
||||
item = Todo.new
|
||||
item.attributes = @params["new_item"]
|
||||
|
||||
# Convert the date format entered (as set in config/settings.yml)
|
||||
# to the mysql format YYYY-MM-DD
|
||||
if @params["new_item"]["due"] != ""
|
||||
date_fmt = app_configurations["formats"]["date"]
|
||||
formatted_date = DateTime.strptime(@params["new_item"]["due"], "#{date_fmt}")
|
||||
item.due = formatted_date.strftime("%Y-%m-%d")
|
||||
else
|
||||
item.due = "0000-00-00"
|
||||
end
|
||||
|
||||
if item.save
|
||||
flash["confirmation"] = "Next action was successfully added"
|
||||
redirect_to( :action => "list" )
|
||||
else
|
||||
flash["warning"] = "Couldn't add the action"
|
||||
redirect_to( :action => "list" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def edit
|
||||
@item = Todo.find(@params['id'])
|
||||
@belongs = @item.project_id
|
||||
@page_title = "Edit task: #{@item.description}"
|
||||
@places = Context.find_all
|
||||
@projects = Project.find_all
|
||||
end
|
||||
|
||||
|
||||
def update
|
||||
@item = Todo.find(@params['item']['id'])
|
||||
@item.attributes = @params['item']
|
||||
if @item.save
|
||||
flash["confirmation"] = 'Next action was successfully updated'
|
||||
redirect_to :action => 'list'
|
||||
else
|
||||
flash["warning"] = 'Next action could not be updated'
|
||||
redirect_to :action => 'list'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def destroy
|
||||
item = Todo.find(@params['id'])
|
||||
if item.destroy
|
||||
flash["confirmation"] = "Next action was successfully deleted"
|
||||
redirect_to :action => "list"
|
||||
else
|
||||
flash["warning"] = "Couldn't delete next action"
|
||||
redirect_to :action => "list"
|
||||
end
|
||||
end
|
||||
|
||||
# Toggles the 'done' status of the action
|
||||
#
|
||||
def toggle_check
|
||||
item = Todo.find(@params['id'])
|
||||
|
||||
case item.done
|
||||
when 0: item.done = 1; item.completed = Time.now()
|
||||
when 1: item.done = 0; item.completed = nil
|
||||
end
|
||||
|
||||
if item.save
|
||||
flash["confirmation"] = "Next action marked as completed"
|
||||
redirect_to( :action => "list" )
|
||||
else
|
||||
flash["warning"] = "Couldn't mark action as completed"
|
||||
redirect_to( :action => "list" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
51
tracks/app/helpers/application_helper.rb
Normal file
51
tracks/app/helpers/application_helper.rb
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# The methods added to this helper will be available to all templates in the application.
|
||||
module ApplicationHelper
|
||||
#require_dependency 'date'
|
||||
|
||||
def format_date(date)
|
||||
# Convert a date object to the format specified
|
||||
# in config/settings.yml
|
||||
#
|
||||
date_fmt = app_configurations["formats"]["date"]
|
||||
formatted_date = date.strftime("#{date_fmt}")
|
||||
end
|
||||
|
||||
def markdown(text)
|
||||
# Uses RedCloth to transform text using either Textile or Markdown
|
||||
# Need to require redcloth above
|
||||
# RedCloth 3.0 or greater is needed to use Markdown, otherwise it only handles Textile
|
||||
#
|
||||
RedCloth.new(text).to_html
|
||||
end
|
||||
|
||||
def tag_object(object, tag)
|
||||
# Wraps object in HTML tags, tag
|
||||
#
|
||||
tagged = "<#{tag}>#{object}</#{tag}>"
|
||||
end
|
||||
|
||||
def due_date(due)
|
||||
# Check due date in comparison to today's date
|
||||
# Flag up date appropriately with a 'traffic light' colour code
|
||||
#
|
||||
if due == nil
|
||||
return ""
|
||||
end
|
||||
|
||||
@now = Date.today
|
||||
@days = due-@now
|
||||
case @days
|
||||
# overdue or due very soon! sound the alarm!
|
||||
when -365..1
|
||||
"<span class=\"red\">" + format_date(due) + "</span> "
|
||||
# due 2-7 days away
|
||||
when 2..7
|
||||
"<span class=\"amber\">" + format_date(due) + "</span> "
|
||||
# more than a week away - relax
|
||||
else
|
||||
"<span class=\"green\">" + format_date(due) + "</span> "
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
2
tracks/app/helpers/context_helper.rb
Normal file
2
tracks/app/helpers/context_helper.rb
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
module ContextHelper
|
||||
end
|
||||
34
tracks/app/helpers/feed_helper.rb
Normal file
34
tracks/app/helpers/feed_helper.rb
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
module FeedHelper
|
||||
|
||||
# Build a nicely formatted text string for display
|
||||
# Context forms the heading, then the items are
|
||||
# indented underneath. If there is a due date
|
||||
# and the item is in a project, these are also displayed
|
||||
#
|
||||
def build_text_page(list,contexts,projects)
|
||||
result_string = ""
|
||||
for @place in @places
|
||||
result_string << "\n" + @place.name.upcase + ":\n"
|
||||
|
||||
list.each do |@item|
|
||||
if @item.context_id == @place.id
|
||||
|
||||
if @item.due
|
||||
result_string << " [" + format_date(@item.due) + "] "
|
||||
result_string << @item.description + " "
|
||||
else
|
||||
result_string << " " + @item.description + " "
|
||||
end
|
||||
|
||||
if @item.project_id
|
||||
result_string << "(" + @item.project['name'] + ")"
|
||||
end
|
||||
result_string << "\n"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
return result_string
|
||||
end
|
||||
|
||||
end
|
||||
18
tracks/app/helpers/login_helper.rb
Normal file
18
tracks/app/helpers/login_helper.rb
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
module LoginHelper
|
||||
|
||||
|
||||
def render_errors(obj)
|
||||
return "" unless obj
|
||||
return "" unless @request.post?
|
||||
tag = String.new
|
||||
|
||||
unless obj.valid?
|
||||
tag << %{<ul class="objerrors">}
|
||||
obj.errors.each_full { |message| tag << %{<li>#{message}</li>} }
|
||||
tag << %{</ul>}
|
||||
end
|
||||
tag
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
2
tracks/app/helpers/project_helper.rb
Normal file
2
tracks/app/helpers/project_helper.rb
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
module ProjectHelper
|
||||
end
|
||||
36
tracks/app/helpers/todo_helper.rb
Normal file
36
tracks/app/helpers/todo_helper.rb
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
module TodoHelper
|
||||
|
||||
|
||||
def display_done(ary,context)
|
||||
result_string = ""
|
||||
result_string << "<ul>"
|
||||
ary.each do |@item|
|
||||
result_string << "<li>" + @item.description + " "
|
||||
|
||||
# Item should have a completion date if it is done
|
||||
# This is just a sanity check
|
||||
#
|
||||
if @item.completed != nil
|
||||
result_string << "[completed: " + format_date(@item.completed) + "]" + " "
|
||||
end
|
||||
|
||||
result_string << "in " + @item.context['name'].capitalize + "</li>"
|
||||
end
|
||||
result_string << "</ul>"
|
||||
return result_string
|
||||
end
|
||||
|
||||
|
||||
def count_items(items, context)
|
||||
# Count the number of items in the selected context
|
||||
#
|
||||
count = 0
|
||||
for item in items
|
||||
if item.context['name'] == context
|
||||
count += 1
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
end
|
||||
3
tracks/app/models/context.rb
Normal file
3
tracks/app/models/context.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
class Context < ActiveRecord::Base
|
||||
has_many :todo, :dependent => true
|
||||
end
|
||||
3
tracks/app/models/project.rb
Normal file
3
tracks/app/models/project.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
class Project < ActiveRecord::Base
|
||||
has_many :todo, :dependent => true
|
||||
end
|
||||
16
tracks/app/models/todo.rb
Normal file
16
tracks/app/models/todo.rb
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
class Todo < ActiveRecord::Base
|
||||
|
||||
belongs_to :context
|
||||
belongs_to :project
|
||||
|
||||
def before_save
|
||||
# Add a creation date (Ruby object format) to item before it's saved
|
||||
# if there is no existing creation date (this prevents creation date
|
||||
# being reset to completion date when item is completed)
|
||||
#
|
||||
if self.created == nil
|
||||
self.created = Time.now()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
30
tracks/app/models/user.rb
Normal file
30
tracks/app/models/user.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
require 'digest/sha1'
|
||||
|
||||
# this model expects a certain database layout and its based on the name/login pattern.
|
||||
class User < ActiveRecord::Base
|
||||
|
||||
def self.authenticate(login, pass)
|
||||
find_first(["login = ? AND password = ?", login, sha1(pass)])
|
||||
end
|
||||
|
||||
def change_password(pass)
|
||||
update_attribute "password", self.class.sha1(pass)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.sha1(pass)
|
||||
Digest::SHA1.hexdigest("change-me--#{pass}--")
|
||||
end
|
||||
|
||||
before_create :crypt_password
|
||||
|
||||
def crypt_password
|
||||
write_attribute("password", self.class.sha1(password)) if password == @password_confirmation
|
||||
end
|
||||
|
||||
validates_length_of :password, :login, :within => 5..40
|
||||
validates_presence_of :password, :login
|
||||
validates_uniqueness_of :login, :on => :create
|
||||
validates_confirmation_of :password, :on => :create
|
||||
end
|
||||
32
tracks/app/views/context/list.rhtml
Normal file
32
tracks/app/views/context/list.rhtml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<div id="display_box">
|
||||
|
||||
<table cellpadding="5" width="450">
|
||||
<% row = 1 %>
|
||||
<% for @context in @contexts %>
|
||||
<% if row % 2 == 0 %>
|
||||
<tr class="even_row">
|
||||
<% else %>
|
||||
<tr class="odd_row">
|
||||
<% end %>
|
||||
<td align="right" width="20"><%= @context.id.to_s %></td>
|
||||
<td width="390"><%= link_to( "#{@context.name.capitalize}", :action => "show", :id => @context.id ) %></td>
|
||||
<td width="40"><%= link_to($edit_img, { :action => "edit", :id => @context.id }, :title => "Edit item" ) + " " + link_to($delete_img, { :action => "destroy", :id => @context.id }, :title => "Delete item", :confirm => "Are you sure you want to delete this context: #{@context.name}. Any todos in this context will be deleted.") + " " %></td>
|
||||
</tr>
|
||||
<% row += 1 %>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
</div><!- End of display_box -->
|
||||
|
||||
<div id="input_box">
|
||||
<h2>Add context</h2>
|
||||
<form method="post" action="add_context">
|
||||
<label for="new_context_name">New context</label><br />
|
||||
<%= text_field("new_context", "name") %>
|
||||
<br />
|
||||
<input type="submit" value="Add context">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>
|
||||
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %>
|
||||
61
tracks/app/views/context/show.rhtml
Normal file
61
tracks/app/views/context/show.rhtml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<div id="display_box">
|
||||
|
||||
<div class="contexts">
|
||||
<h2><%= @context.name.capitalize %></h2>
|
||||
<ul>
|
||||
<% for @item in @not_done %>
|
||||
<li>
|
||||
<div class="box">
|
||||
<%= check_box( "item", "done", "onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'" ) %>
|
||||
</div>
|
||||
|
||||
<div class="description">
|
||||
<%= due_date(@item.due) %>
|
||||
<%= @item.description %>
|
||||
<% if @item.project_id %>
|
||||
<%= link_to( "[P]", { :controller => "project", :action => "show", :id => @item.project_id }, :title => "View project: #{@item.project['name']}" ) %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="tools">
|
||||
<%= link_to($edit_img, { :controller => "todo", :action => "edit", :id => @item.id }, :title => "Edit item") + " " + link_to($delete_img, { :controller => "todo", :action => "destroy", :id => @item.id }, :title => "Delete item", :confirm => "Are you sure you want to delete this entry: #{@item.description}") + " " %>
|
||||
|
||||
<% if @item.notes? %>
|
||||
<%= "<a href=\"javascript:toggle('" + @item.id.to_s + "')\" title=\"Show notes\">" + $notes_img + "</a>" %></div>
|
||||
<% m_notes = markdown(@item.notes) %>
|
||||
<%= "<div class=\"notes\" id=\"" + @item.id.to_s + "\">" + m_notes + "</div>" %>
|
||||
<% else %>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div><!- End of display_box -->
|
||||
|
||||
<div id="input_box">
|
||||
<h2>Add next action to this context</h2>
|
||||
<%= form_tag( :controller => "context", :action => "add_item") %>
|
||||
<%= hidden_field( "new_item", "context_id", "value" => "#{@context.id}") %>
|
||||
<label for="new_item_description">Next action</label><br />
|
||||
<%= text_field( "new_item", "description" ) %>
|
||||
<br />
|
||||
<label for="new_item_notes">Notes</label><br />
|
||||
<%= text_area( "new_item", "notes", "cols" => 40, "rows" => 15 ) %>
|
||||
<br />
|
||||
<label for="new_item_project_id">Project</label><br />
|
||||
<select name="new_item[project_id]" id="new_item_project_id">
|
||||
<option value="" selected>None</option>
|
||||
<% for @project in @projects %>
|
||||
<option value="<%= @project.id %>"><%= @project.name %></option>
|
||||
<% end %>
|
||||
</select><br />
|
||||
<label for="new_item_due">Due</label><br />
|
||||
<%= text_field( "new_item", "due", {"size" => 10, "maxlength" => 10} ) %>
|
||||
<br />
|
||||
<input type="submit" value="Add item">
|
||||
</form>
|
||||
</div><!-- End of input box -->
|
||||
|
||||
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>
|
||||
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %>
|
||||
14
tracks/app/views/feed/na_feed.rxml
Normal file
14
tracks/app/views/feed/na_feed.rxml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
|
||||
xml.channel do
|
||||
xml.title("Tracks - Next Actions")
|
||||
xml.link("http://#{@request.host}:#{@request.port}/todo/list")
|
||||
xml.description("Lists the last 15 undone next actions")
|
||||
@not_done.each { |i|
|
||||
xml.item do
|
||||
xml.title(i.description)
|
||||
xml.link("http://#{@request.host}:#{@request.port}/context/show/#{i.context_id}")
|
||||
xml.description(i.context['name'].capitalize)
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
1
tracks/app/views/feed/na_text.rhtml
Normal file
1
tracks/app/views/feed/na_text.rhtml
Normal file
|
|
@ -0,0 +1 @@
|
|||
<%= build_text_page( @not_done, @places, @projects ) %>
|
||||
10
tracks/app/views/layouts/scaffold.rhtml
Normal file
10
tracks/app/views/layouts/scaffold.rhtml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Login</title>
|
||||
<link href="/stylesheets/scaffold.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<%= @content_for_layout %>
|
||||
</body>
|
||||
</html>
|
||||
38
tracks/app/views/layouts/standard.rhtml
Normal file
38
tracks/app/views/layouts/standard.rhtml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<style type="text/css" media="screen">
|
||||
@import url(/stylesheets/standard.css);
|
||||
</style>
|
||||
|
||||
<script type="text/javascript" src="/javascripts/toggle_notes.js"></script>
|
||||
|
||||
<title><%= @page_title %></title>
|
||||
</head>
|
||||
<body onload="javascript:toggleAll('notes','none')">
|
||||
<div>
|
||||
<h1>
|
||||
<% if @not_done %>
|
||||
<span class="badge"><%= @not_done.length %></span>
|
||||
<% end %>
|
||||
<%= today = Time.now; datestamp = today.strftime("%A, %e %B %Y") %></h1>
|
||||
</div>
|
||||
<div id="navcontainer">
|
||||
<ul id="navlist">
|
||||
<li><%= link_to( "Home", :controller => "todo", :action => "list" ) %></li>
|
||||
<li><%= link_to( "Contexts", :controller => "context", :action => "list" ) %></li>
|
||||
<li><%= link_to( "Projects", :controller => "project", :action => "list" ) %></li>
|
||||
<li><%= link_to( "Completed", :controller => "todo", :action => "completed" ) %></li>
|
||||
<li><a href="javascript:toggleAll('notes','block')" title="Show all notes">Show</a></li>
|
||||
<li><a href="javascript:toggleAll('notes','none')" title="Show all notes">Hide</a></li>
|
||||
<li><%= link_to "<span style=\"font-family: verdana, sans-serif; font-size: 10px; font-weight:bold; text-decoration:none; color: white; background-color: #F60; border:1px solid;
|
||||
border-color: #FC9 #630 #330 #F96; padding:0px 3px 0px 3px; margin:0px;\">RSS</span>", { :controller => "feed", :action => "na_feed" }, :title => "Subscribe to RSS feed of next actions" %></li>
|
||||
<li><%= link_to "<span style=\"font-family: verdana, sans-serif; font-size: 10px; font-weight:bold; text-decoration:none; color: white; background-color: #F60; border:1px solid;
|
||||
border-color: #FC9 #630 #330 #F96; padding:0px 3px 0px 3px; margin:0px;\">TXT</span>", { :controller => "feed", :action => "na_text" }, :title => "View a plain text list of next actions" %></li>
|
||||
<li><%= link_to "Logout »", :controller => "login", :action=>"logout"%></li>
|
||||
</ul>
|
||||
</div>
|
||||
<%= @content_for_layout %>
|
||||
<div id="footer">made with <a href="http://rubyonrails.org">Ruby on Rails</a></div>
|
||||
</body>
|
||||
</html>
|
||||
22
tracks/app/views/login/login.rhtml
Normal file
22
tracks/app/views/login/login.rhtml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<%= start_form_tag :action=> "login" %>
|
||||
|
||||
<div title="Account login" id="loginform" class="form">
|
||||
<h3>Please log in to use Tracks:</h3>
|
||||
|
||||
<% if @message %>
|
||||
<div id="message"><%= @message %></div>
|
||||
<% end %>
|
||||
|
||||
<label for="user_login">Login: </label>
|
||||
<input type="text" name="user_login" id="user_login" size="30" value=""/><br/>
|
||||
|
||||
<label for="user_password">Password:</label>
|
||||
<input type="password" name="user_password" id="user_password" size="30"/>
|
||||
|
||||
<br/>
|
||||
<input type="submit" name="login" value="Login »" class="primary" />
|
||||
|
||||
</div>
|
||||
|
||||
<%= end_form_tag %>
|
||||
|
||||
10
tracks/app/views/login/logout.rhtml
Normal file
10
tracks/app/views/login/logout.rhtml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
<div class="memo">
|
||||
<h3>Logoff</h3>
|
||||
|
||||
<p>You are now logged out of the system...</p>
|
||||
|
||||
<%= link_to "« login", :action=>"login"%>
|
||||
|
||||
</div>
|
||||
|
||||
17
tracks/app/views/login/signup.rhtml
Normal file
17
tracks/app/views/login/signup.rhtml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<%= start_form_tag :action=> "signup" %>
|
||||
|
||||
<div title="Account signup" id="signupform" class="form">
|
||||
<h3>Signup</h3>
|
||||
<%= render_errors @user %><br/>
|
||||
|
||||
<label for="user_login">Desired login:</label><br/>
|
||||
<%= text_field "user", "login", :size => 30 %><br/>
|
||||
<label for="user_password">Choose password:</label><br/>
|
||||
<%= password_field "user", "password", :size => 30 %><br/>
|
||||
<label for="user_password_confirmation">Confirm password:</label><br/>
|
||||
<%= password_field "user", "password_confirmation", :size => 30 %><br/>
|
||||
|
||||
<input type="submit" value="Signup »" class="primary" />
|
||||
|
||||
<%= end_form_tag %>
|
||||
|
||||
13
tracks/app/views/login/welcome.rhtml
Normal file
13
tracks/app/views/login/welcome.rhtml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
<div class="memo">
|
||||
<h3>Welcome</h3>
|
||||
|
||||
<p>You are now logged into the system...</p>
|
||||
<p>
|
||||
Since you are here it's safe to assume the application never called store_location, otherwise
|
||||
you would have been redirected somewhere else after a successful login.
|
||||
</p>
|
||||
|
||||
<%= link_to "« logout", :action=>"logout"%>
|
||||
|
||||
</div>
|
||||
32
tracks/app/views/project/list.rhtml
Normal file
32
tracks/app/views/project/list.rhtml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<div id="display_box">
|
||||
|
||||
<table cellpadding="5" width="450">
|
||||
<% row = 1 %>
|
||||
<% for @project in @projects %>
|
||||
<% if row % 2 == 0 %>
|
||||
<tr class="even_row">
|
||||
<% else %>
|
||||
<tr class="odd_row">
|
||||
<% end %>
|
||||
<td align="right" width="20"><%= @project.id.to_s %></td>
|
||||
<td width="390"><%= link_to ( "#{@project.name}", :action => "show", :id => @project.id ) %></td>
|
||||
<td width="40"><%= link_to( $edit_img, { :action => "edit", :id => @project.id }, :title => "Edit item" ) + " " + link_to($delete_img, { :action => "destroy", :id => @project.id }, :title => "Delete item", :confirm => "Are you sure you want to delete this context: #{@project.name}. Any todos in this context will be deleted." ) + " " %></td>
|
||||
</tr>
|
||||
<% row += 1 %>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
</div><!- End of display_box -->
|
||||
|
||||
<div id="input_box">
|
||||
<h2>Add project</h2>
|
||||
<form method="post" action="add_project">
|
||||
<label for="new_project_name">New Project</label><br />
|
||||
<%= text_field( "new_project", "name" ) %>
|
||||
<br />
|
||||
<input type="submit" value="Add project">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>
|
||||
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %>
|
||||
65
tracks/app/views/project/show.rhtml
Normal file
65
tracks/app/views/project/show.rhtml
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<div id="display_box">
|
||||
|
||||
<div class="contexts">
|
||||
<h2><%= @project.name %></h2>
|
||||
|
||||
<% if @not_done == [] %>
|
||||
<p>There are no next actions yet in this project</p>
|
||||
<% else %>
|
||||
<ul>
|
||||
<% for @item in @not_done %>
|
||||
<li>
|
||||
<div class="box">
|
||||
<%= check_box( "item", "done", "onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'" ) %>
|
||||
</div>
|
||||
|
||||
<div class="description">
|
||||
<%= due_date( @item.due ) %>
|
||||
<%= @item.description %>
|
||||
<%= link_to( "[C]", { :controller => "context", :action => "show", :id => @item.context_id }, :title => "View context: #{@item.context['name'].capitalize}" ) %>
|
||||
</div>
|
||||
|
||||
<div class="tools">
|
||||
<%= link_to( $edit_img, { :controller => "todo", :action => "edit", :id => @item.id }, :title => "Edit item" ) + " " + link_to($delete_img, { :controller => "todo", :action => "destroy", :id => @item.id }, :title => "Delete item", :confirm => "Are you sure you want to delete this entry: #{@item.description}" ) + " " %>
|
||||
|
||||
<% if @item.notes? %>
|
||||
<%= "<a href=\"javascript:toggle('" + @item.id.to_s + "')\" title=\"Show notes\">" + $notes_img + "</a>" %></div>
|
||||
<% m_notes = markdown(@item.notes) %>
|
||||
<%= "<div class=\"notes\" id=\"" + @item.id.to_s + "\">" + m_notes + "</div>" %>
|
||||
<% else %>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div><!-- End of display box -->
|
||||
|
||||
<div id="input_box">
|
||||
<h2>Add next action to this project</h2>
|
||||
<%= form_tag( :controller => "project", :action => "add_item") %>
|
||||
<%= hidden_field( "new_item", "project_id", "value" => "#{@project.id}") %>
|
||||
<label for="new_item_description">Next action</label><br />
|
||||
<%= text_field( "new_item", "description" ) %>
|
||||
<br />
|
||||
<label for="new_item_notes">Notes</label><br />
|
||||
<%= text_area( "new_item", "notes", "cols" => 40, "rows" => 15 ) %>
|
||||
<br />
|
||||
<label for="new_item_context_id">Context</label><br />
|
||||
<select name="new_item[context_id]" id="new_item_context_id">
|
||||
<% for @place in @places %>
|
||||
<option value="<%= @place.id %>"><%= @place.name.capitalize %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
<br />
|
||||
<label for="new_item_due">Due</label><br />
|
||||
<%= text_field( "new_item", "due", {"size" => 10, "maxlength" => 10} ) %>
|
||||
<br />
|
||||
<input type="submit" value="Add item">
|
||||
</form>
|
||||
</div><!-- End of input box -->
|
||||
|
||||
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>
|
||||
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %>
|
||||
29
tracks/app/views/todo/_done.rhtml
Normal file
29
tracks/app/views/todo/_done.rhtml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<% @item = done %>
|
||||
<li>
|
||||
<% if @item.completed %>
|
||||
<div class="box">
|
||||
<%= $done_img %>
|
||||
</div>
|
||||
|
||||
<div class="description">
|
||||
<span class="grey"><%= format_date( @item.completed ) %></span>
|
||||
<%= " " + @item.description + " "%>
|
||||
|
||||
<% if @item.project_id %>
|
||||
<%= "(" + @item.context['name'].capitalize + ", " + @item.project['name'] + ")" %>
|
||||
<% else %>
|
||||
<%= "(" + @item.context['name'].capitalize + ")" %>
|
||||
<% end %>
|
||||
|
||||
<% if @item.due %>
|
||||
<%= " - was due on " + format_date( @item.due ) %>
|
||||
<% end %>
|
||||
|
||||
<% if @item.notes? %>
|
||||
<%= "<a href=\"javascript:toggle('" + @item.id.to_s + "')\" title=\"Show notes\">" + $notes_img + "</a>" %>
|
||||
<% m_notes = markdown( @item.notes ) %>
|
||||
<%= "<div class=\"notes\" id=\"" + @item.id.to_s + "\">" + m_notes + "</div>" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
10
tracks/app/views/todo/completed.rhtml
Normal file
10
tracks/app/views/todo/completed.rhtml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<div id="display_box_projects">
|
||||
|
||||
<div class="contexts">
|
||||
<h2>Completed items</h2>
|
||||
<ul>
|
||||
<%= render_collection_of_partials "done", @done %>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div><!- End of display_box -->
|
||||
48
tracks/app/views/todo/edit.rhtml
Normal file
48
tracks/app/views/todo/edit.rhtml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<div id="display_box">
|
||||
<h2>Update task</h2>
|
||||
<form action="/todo/update" method="post">
|
||||
<%= hidden_field( "item", "id" ) %>
|
||||
|
||||
<p><label for="item_description">Description</label><br />
|
||||
<%= text_field( "item", "description" ) %></p>
|
||||
|
||||
<p><label for="item_notes">Notes</label><br />
|
||||
<%= text_area( "item", "notes" ) %></p>
|
||||
|
||||
<p><label for="item_context_id">Context</label><br />
|
||||
<select name="item[context_id]" id="item_context_id">
|
||||
<% for @place in @places %>
|
||||
<% if @place.id == @item.context_id %>
|
||||
<option value="<%= @place.id %>" selected="selected"><%= @place.name.capitalize %></option>
|
||||
<% else %>
|
||||
<option value="<%= @place.id %>"><%= @place.name.capitalize %></option>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</select></p>
|
||||
|
||||
<p><label for="new_item_project_id">Project</label><br />
|
||||
<select name="item[project_id]" id="item_project_id">
|
||||
<% if @belongs == nil %>
|
||||
<option value="" selected="selected">None</option>
|
||||
<% end %>
|
||||
|
||||
<% for @project in @projects %>
|
||||
<% if @project.id == @belongs %>
|
||||
<option value="<%= @project.id %>" selected="selected"><%= @project.name %></option>
|
||||
<% else %>
|
||||
<option value="<%= @project.id %>"><%= @project.name %></option>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</select></p>
|
||||
|
||||
<p><label for="item_due">Due (YYYY-MM-DD)</label><br />
|
||||
<%= text_field( "item", "due" ) %></p>
|
||||
|
||||
<p><input type="submit" value="Update" /></p>
|
||||
</form>
|
||||
|
||||
<%= link_to 'Cancel', :action => 'list' %>
|
||||
</div>
|
||||
|
||||
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>
|
||||
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %>
|
||||
89
tracks/app/views/todo/list.rhtml
Normal file
89
tracks/app/views/todo/list.rhtml
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<div id="display_box">
|
||||
|
||||
<% for @place in @places %>
|
||||
<% heading = false %>
|
||||
|
||||
<% for @item in @not_done %>
|
||||
<% if @place.name == @item.context['name'] %>
|
||||
|
||||
<% if ( Todo.find_all( "context_id=#{@item.context['id']}" ) && heading == false ) %>
|
||||
<div class="contexts">
|
||||
<h2><%= link_to( "#{@item.context['name'].capitalize}", :controller => "context", :action => "show", :id => @item.context_id ) %></h2>
|
||||
<ul>
|
||||
<% heading = true %>
|
||||
<% end %>
|
||||
|
||||
<li>
|
||||
<div class="box">
|
||||
<%= check_box( "item", "done", "onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'" ) %>
|
||||
</div>
|
||||
|
||||
<div class="description">
|
||||
<%= due_date( @item.due ) %>
|
||||
<%= @item.description %>
|
||||
<% if @item.project_id %>
|
||||
<%= link_to( "[P]", { :controller => "project", :action => "show", :id => @item.project_id }, :title => "View project: #{@item.project['name']}" ) %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="tools">
|
||||
<%= link_to( $edit_img, { :action => "edit", :id => @item.id }, :title => "Edit item" ) + " " + link_to($delete_img, { :action => "destroy", :id => @item.id }, :title => "Delete item", :confirm => "Are you sure you want to delete this entry: #{@item.description}" ) + " " %>
|
||||
|
||||
<% if @item.notes? %>
|
||||
<%= "<a href=\"javascript:toggle('" + @item.id.to_s + "')\" title=\"Show notes\">" + $notes_img + "</a>" %></div>
|
||||
<% m_notes = markdown( @item.notes ) %>
|
||||
<%= "<div class=\"notes\" id=\"" + @item.id.to_s + "\">" + m_notes + "</div>" %>
|
||||
<% else %>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if heading == true %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<div class="contexts">
|
||||
<h2>Last 5 completed actions</h2>
|
||||
<ul>
|
||||
<%= render_collection_of_partials "done", @done %>
|
||||
</ul>
|
||||
</div>
|
||||
</div><!- End of display_box -->
|
||||
|
||||
<div id="input_box">
|
||||
<h2>Add next action</h2>
|
||||
<form method="post" action="add_item">
|
||||
<label for="new_item_description">Next action</label><br />
|
||||
<%= text_field( "new_item", "description" ) %>
|
||||
<br />
|
||||
<label for="new_item_notes">Notes</label><br />
|
||||
<%= text_area( "new_item", "notes", "cols" => 40, "rows" => 15 ) %>
|
||||
<br />
|
||||
<label for="new_item_context_id">Context</label><br />
|
||||
<select name="new_item[context_id]" id="new_item_context_id">
|
||||
<% for @place in @places %>
|
||||
<option value="<%= @place.id %>"><%= @place.name.capitalize %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
<br />
|
||||
<label for="new_item_project_id">Project</label><br />
|
||||
<select name="new_item[project_id]" id="new_item_project_id">
|
||||
<option value="" selected>None</option>
|
||||
<% for @project in @projects %>
|
||||
<option value="<%= @project.id %>"><%= @project.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
<br />
|
||||
<label for="new_item_due">Due</label><br />
|
||||
<%= text_field( "new_item", "due", {"size" => 10, "maxlength" => 10} ) %>
|
||||
<br />
|
||||
<input type="submit" value="Add item">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>
|
||||
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %>
|
||||
20
tracks/config/database.yml.tmpl
Normal file
20
tracks/config/database.yml.tmpl
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
development:
|
||||
adapter: mysql
|
||||
database: tracks
|
||||
host: localhost
|
||||
username: root
|
||||
password:
|
||||
|
||||
test:
|
||||
adapter: mysql
|
||||
database: tracks_test
|
||||
host: localhost
|
||||
username: root
|
||||
password:
|
||||
|
||||
production:
|
||||
adapter: mysql
|
||||
database: tracks
|
||||
host: localhost
|
||||
username: root
|
||||
password:
|
||||
63
tracks/config/environment.rb
Normal file
63
tracks/config/environment.rb
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
RAILS_ROOT = File.dirname(__FILE__) + "/../"
|
||||
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
|
||||
|
||||
|
||||
# Mocks first.
|
||||
ADDITIONAL_LOAD_PATHS = ["#{RAILS_ROOT}/test/mocks/#{RAILS_ENV}"]
|
||||
|
||||
# Then model subdirectories.
|
||||
ADDITIONAL_LOAD_PATHS.concat(Dir["#{RAILS_ROOT}/app/models/[_a-z]*"])
|
||||
|
||||
# Followed by the standard includes.
|
||||
ADDITIONAL_LOAD_PATHS.concat %w(
|
||||
app
|
||||
app/models
|
||||
app/controllers
|
||||
app/helpers
|
||||
config
|
||||
lib
|
||||
vendor
|
||||
).map { |dir| "#{RAILS_ROOT}/#{dir}" }
|
||||
|
||||
# Prepend to $LOAD_PATH
|
||||
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) }
|
||||
|
||||
|
||||
# Require Rails gems.
|
||||
require 'rubygems'
|
||||
require_gem 'activerecord'
|
||||
require_gem 'actionpack'
|
||||
require_gem 'actionmailer'
|
||||
require_gem 'rails'
|
||||
|
||||
|
||||
# Environment-specific configuration.
|
||||
require_dependency "environments/#{RAILS_ENV}"
|
||||
ActiveRecord::Base.configurations = YAML::load(File.open("#{RAILS_ROOT}/config/database.yml"))
|
||||
ActiveRecord::Base.establish_connection
|
||||
|
||||
|
||||
# Configure defaults if the included environment did not.
|
||||
begin
|
||||
RAILS_DEFAULT_LOGGER = Logger.new("#{RAILS_ROOT}/log/#{RAILS_ENV}.log")
|
||||
rescue StandardError
|
||||
RAILS_DEFAULT_LOGGER = Logger.new(STDERR)
|
||||
RAILS_DEFAULT_LOGGER.level = Logger::WARN
|
||||
RAILS_DEFAULT_LOGGER.warn(
|
||||
"Rails Error: Unable to access log file. Please ensure that log/#{RAILS_ENV}.log exists and is chmod 0777. " +
|
||||
"The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
|
||||
)
|
||||
end
|
||||
|
||||
[ActiveRecord::Base, ActionController::Base, ActionMailer::Base].each do |klass|
|
||||
klass.logger ||= RAILS_DEFAULT_LOGGER
|
||||
end
|
||||
[ActionController::Base, ActionMailer::Base].each do |klass|
|
||||
klass.template_root ||= "#{RAILS_ROOT}/app/views/"
|
||||
end
|
||||
|
||||
|
||||
# Include your app's configuration here:
|
||||
def app_configurations
|
||||
YAML::load(File.open("#{RAILS_ROOT}/config/settings.yml"))
|
||||
end
|
||||
3
tracks/config/environments/development.rb
Normal file
3
tracks/config/environments/development.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Dependencies.mechanism = :load
|
||||
ActionController::Base.consider_all_requests_local = true
|
||||
BREAKPOINT_SERVER_PORT = 42531
|
||||
2
tracks/config/environments/production.rb
Normal file
2
tracks/config/environments/production.rb
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Dependencies.mechanism = :require
|
||||
ActionController::Base.consider_all_requests_local = false
|
||||
3
tracks/config/environments/test.rb
Normal file
3
tracks/config/environments/test.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Dependencies.mechanism = :require
|
||||
ActionController::Base.consider_all_requests_local = true
|
||||
ActionMailer::Base.delivery_method = :test
|
||||
2
tracks/config/settings.yml.tmpl
Normal file
2
tracks/config/settings.yml.tmpl
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
formats:
|
||||
date: %d/%m/%Y
|
||||
88
tracks/db/tracks_dump 03.01.2005.sql
Normal file
88
tracks/db/tracks_dump 03.01.2005.sql
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# CocoaMySQL dump
|
||||
# Version 0.5
|
||||
# http://cocoamysql.sourceforge.net
|
||||
#
|
||||
# Host: localhost (MySQL 4.0.20-max)
|
||||
# Database: todo
|
||||
# Generation Time: 2005-01-03 14:14:18 +0000
|
||||
# ************************************************************
|
||||
|
||||
# Dump of table contexts
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `contexts` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`name` varchar(255) NOT NULL default '',
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=MyISAM;
|
||||
|
||||
INSERT INTO `contexts` (`id`,`name`) VALUES ("1","agenda");
|
||||
INSERT INTO `contexts` (`id`,`name`) VALUES ("2","call");
|
||||
INSERT INTO `contexts` (`id`,`name`) VALUES ("3","email");
|
||||
INSERT INTO `contexts` (`id`,`name`) VALUES ("4","errand");
|
||||
INSERT INTO `contexts` (`id`,`name`) VALUES ("5","lab");
|
||||
INSERT INTO `contexts` (`id`,`name`) VALUES ("6","library");
|
||||
INSERT INTO `contexts` (`id`,`name`) VALUES ("7","freetime");
|
||||
INSERT INTO `contexts` (`id`,`name`) VALUES ("8","office");
|
||||
INSERT INTO `contexts` (`id`,`name`) VALUES ("11","waiting-for");
|
||||
|
||||
|
||||
# Dump of table projects
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `projects` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`name` varchar(255) NOT NULL default '',
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=MyISAM;
|
||||
|
||||
INSERT INTO `projects` (`id`,`name`) VALUES ("1","Build a working time machine");
|
||||
INSERT INTO `projects` (`id`,`name`) VALUES ("2","Make more money than Billy Gates");
|
||||
INSERT INTO `projects` (`id`,`name`) VALUES ("3","Evict dinosaurs from the garden");
|
||||
|
||||
|
||||
# Dump of table todos
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `todos` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`context_id` int(11) NOT NULL default '0',
|
||||
`description` varchar(100) NOT NULL default '',
|
||||
`notes` text,
|
||||
`done` tinyint(4) NOT NULL default '0',
|
||||
`created` datetime NOT NULL default '0000-00-00 00:00:00',
|
||||
`due` date default NULL,
|
||||
`completed` datetime default NULL,
|
||||
`project_id` int(11) default NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=MyISAM;
|
||||
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("1","1","Call Bill Gates to find out how much he makes per day","","0","2004-11-28 16:01:00","2004-10-30",NULL,"2");
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("52","2","Call dinosaur exterminator","Ask him if I need to hire a skip for the corpses.","0","2004-11-28 16:06:08","2004-11-30",NULL,"3");
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("53","4","Buy milk","","1","2004-11-28 16:06:31","0000-00-00","2004-11-28 16:06:42",NULL);
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("54","4","Buy bread","","1","2004-11-28 16:06:58","0000-00-00","2004-11-30 13:41:09",NULL);
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("55","5","Construct time dilation device","","0","2004-11-28 16:07:33","0000-00-00",NULL,"1");
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("56","2","Phone Grandfather to ask about the paradox","Added some _notes_.","0","2004-11-28 16:08:33","2004-12-30",NULL,"1");
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("61","6","Get a book out of the library","Dinosaurs\'R\'Us","0","2004-12-22 14:07:06","0000-00-00",NULL,"3");
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("60","4","Upgrade to Rails 0.9.1","","1","2004-12-20 17:02:52","2004-12-21","2004-12-20 17:06:48",NULL);
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("65","1","This should be due today","","0","2004-12-31 17:23:06","2004-12-31",NULL,NULL);
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("75","1","foo","","1","2004-12-31 18:38:34","2005-01-05","2005-01-02 12:27:10",NULL);
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("81","1","Buy shares","","0","2005-01-01 12:40:26","2005-02-01",NULL,"2");
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("85","1","Buy stegosaurus bait","","1","2005-01-01 12:53:12","2005-01-02","2005-01-01 12:53:43","3");
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("92","1","New action in context","Some notes","1","2005-01-02 14:52:49","2005-03-01","2005-01-02 15:44:19","3");
|
||||
INSERT INTO `todos` (`id`,`context_id`,`description`,`notes`,`done`,`created`,`due`,`completed`,`project_id`) VALUES ("97","2","Call stock broker","tel: 12345","0","2005-01-03 11:38:25","0000-00-00",NULL,"2");
|
||||
|
||||
|
||||
# Dump of table users
|
||||
# ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`login` varchar(80) default NULL,
|
||||
`password` varchar(40) default NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) TYPE=MyISAM;
|
||||
|
||||
INSERT INTO `users` (`id`,`login`,`password`) VALUES ("1","test","9a91e1d8d95b6315991a88121bb0aa9f03ba0dfc");
|
||||
|
||||
|
||||
34
tracks/doc/CHANGENOTES.txt
Normal file
34
tracks/doc/CHANGENOTES.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
## Tracks :: GTD web application
|
||||
## $LastChangedDate$
|
||||
## $HeadURL$
|
||||
|
||||
Main project site: <http://www.rousette.org.uk/projects/>
|
||||
Project wiki: <http://www.rousette.org.uk/projects/wiki/>
|
||||
|
||||
## Version 1.01
|
||||
|
||||
A small increment to fix a few bugs and typographical errors in the README:
|
||||
|
||||
1. README.txt now lists the correct location for the dump file
|
||||
2. Fixed the redirection from the login page. Once you have signed up or logged in, you should be taken automatically to the main todo/list page. This also works once you have logged out and clicked the "<< login" page to get back to login/login. (Thanks, Max Prophet!)
|
||||
3. Properly updated for Rails 0.9.3: this probably means that it won't work for a lower version of Rails. If you have the gems version of Rails installed, you can update it with:
|
||||
sudo gem update rails
|
||||
4. Made some minor changes to the appearance of the listed items, so that the description wraps properly, and the tool buttons (edit, delete and notes) are always in the same place relative to the checkbox.
|
||||
|
||||
## Version 1.0
|
||||
|
||||
1. Updated to run on Rails 0.9.1. This should work with any 0.9.x branch.
|
||||
2. Added a proper edit page for todos. This also allows you to add a todo to a project, or re-assign it to a new project.
|
||||
3. Improved the efficiency of the Projects page: it now only finds the Project you've selected, rather than all of them (thanks, Johan <http://theexciter.com/>!)
|
||||
4. You now get a warning if you try to delete a project or context with undone items. If you choose to continue, the dependent items will be deleted, so that the list page should no longer break.
|
||||
5. Using Redcloth for markup now that it allows you to use either Textile or Markdown format transparently. This is now included in the distribution, so that you don't need to install it.
|
||||
6. Added links to context/list page so that you can go directly to todo/show/blah if you click the link for context 'blah'.
|
||||
7. You can now set the date format you want to use in the file config/settings.yml. Use the strftime formats, with whatever separator you like. e.g. If you want 2004-12-31, the correct format is %Y-%m-%d. 31/12/2004 would be %d/%m/%Y. The same format is used for entry of the date in the due date box, and for display of the date in the list.
|
||||
8. You can now add a new item to a particular project when you are viewing it at /project/show/[id]. This makes it easy to add a block of next actions to a project. Edit and delete buttons work on this page, but redirect you to /todo/list. I need to fix this.
|
||||
9. Added a login system by using the login_generator:
|
||||
<http://wiki.rubyonrails.com/rails/show/LoginGenerator>
|
||||
The first time you access the system, you need to visit <http://[tracks_url]/login/signup> to enter a username and password. Then when you visit, you will be greeted with a login page. This stores a temporary cookie for your session. The whole app is protected by the login.
|
||||
10. You can now add a new item to a particular context when you are viewing it at /context/show/[id]. This makes it easy to add a block of next actions to a project. Edit and delete buttons work on this page, but redirect you to /todo/list. I need to fix this.
|
||||
11. Feeds! There's an RSS feed available at <http://[tracks_url]/feed/na_feed> which shows the last 15 next actions, and a text feed at <http://[tracks_url]/feed/na_text> which gives you a plain text list of all your next actions, sorted by context. You can use the latter to display your next actions on the desktop with GeekTool. Simply set up a shell command containing the following:
|
||||
curl http://[tracks_url]/feed/na_text
|
||||
Obviously, you need to replace [tracks_url] with the actual URL to the Tracks application.
|
||||
40
tracks/doc/README.txt
Normal file
40
tracks/doc/README.txt
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
Tracks: a GTD web application, built with Ruby on Rails
|
||||
-------------------------------------------------------------
|
||||
|
||||
## $LastChangedDate$
|
||||
## $HeadURL$
|
||||
|
||||
# Homepage:: http://www.rousette.org.uk/projects/
|
||||
# Author:: bsag (http://www.rousette.org.uk/)
|
||||
# Version:: 1.01
|
||||
# Copyright:: (cc) 2004-2005 rousette.org.uk
|
||||
# License:: GNU GPL
|
||||
|
||||
This is a still a work in progress, and there's almost no error checking or validation of the data yet. Use caution when you run it, and make sure that you back up any important data. Full changenotes can be found in tracks/doc/CHANGENOTES.txt. Full API documentation can be found at tracks/doc/app/index.html.
|
||||
|
||||
**IF THIS CRASHES YOUR MACHINE AND LOSES YOUR DATA, IT'S NOT MY FAULT!**
|
||||
|
||||
## Installation
|
||||
|
||||
Before you start, you need to make sure that you have Ruby 1.8.x, mySQL and Rails 0.9.x. Note particularly the last requirement: this will probably not work with Rails 0.8.x. I have now included RedCloth 3.0 (which allows both Textile and Markdown format in the notes field) in the distribution. Find out more about RedCloth here:
|
||||
<http://www.whytheluckystiff.net/ruby/redcloth/>
|
||||
It's licensed under a BSD license.
|
||||
|
||||
1. Unzip tracks.zip somewhere in your home folder ( e.g. /Users/yourusername/Sites).
|
||||
2. Make a mySQL database called tracks for which you have full access rights.
|
||||
3. Import the tables and contents using the tracks_dump 03.01.2005.sql file (in tracks/db). If you have previously used the application, export the contents of the tables from your old todo database and import them into the tracks database.
|
||||
4. Open the tracks/config/database.yml file, and enter your username and password details.
|
||||
5. Open the tracks/config/setting.yml file, and enter your desired format for dates (see CHANGENOTES.txt for details).
|
||||
6. Open Terminal and navigate to the todo folder in your Sites folder.
|
||||
7. Run the command: ruby script/server --environment=production
|
||||
If you already have the previous GTD application running, make sure that you stop the server, or run Tracks on a different port with ruby script/server --environment=production --port=3030
|
||||
8. *IMPORTANT* Tracks now has password protection on all the browser accessible files. The first time that you access it, you need to visit <http://127.0.0.1:3000/login/signup>. Choose your username and password, and you will be directed back to the main listing page (<http://127.0.0.1:3000/todo/list>).
|
||||
9. Have fun!
|
||||
|
||||
## Contacting me
|
||||
|
||||
I'd love any suggestions you have for improvements, bug-fixes etc. Email me on:
|
||||
butshesagirl@rousette.org.uk
|
||||
|
||||
You can also leave bug reports, feature requests, and comments at:
|
||||
<http://www.rousette.org.uk/projects/wiki/>
|
||||
87
tracks/lib/login_system.rb
Normal file
87
tracks/lib/login_system.rb
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
require_dependency "user"
|
||||
|
||||
module LoginSystem
|
||||
|
||||
protected
|
||||
|
||||
# overwrite this if you want to restrict access to only a few actions
|
||||
# or if you want to check if the user has the correct rights
|
||||
# example:
|
||||
#
|
||||
# # only allow nonbobs
|
||||
# def authorize?(user)
|
||||
# user.login != "bob"
|
||||
# end
|
||||
def authorize?(user)
|
||||
true
|
||||
end
|
||||
|
||||
# overwrite this method if you only want to protect certain actions of the controller
|
||||
# example:
|
||||
#
|
||||
# # don't protect the login and the about method
|
||||
# def protect?(action)
|
||||
# if ['action', 'about'].include?(action)
|
||||
# return false
|
||||
# else
|
||||
# return true
|
||||
# end
|
||||
# end
|
||||
def protect?(action)
|
||||
true
|
||||
end
|
||||
|
||||
# login_required filter. add
|
||||
#
|
||||
# before_filter :login_required
|
||||
#
|
||||
# if the controller should be under any rights management.
|
||||
# for finer access control you can overwrite
|
||||
#
|
||||
# def authorize?(user)
|
||||
#
|
||||
def login_required
|
||||
|
||||
if not protect?(action_name)
|
||||
return true
|
||||
end
|
||||
|
||||
if @session['user'] and authorize?(@session['user'])
|
||||
return true
|
||||
end
|
||||
|
||||
# store current location so that we can
|
||||
# come back after the user logged in
|
||||
store_location
|
||||
|
||||
# call overwriteable reaction to unauthorized access
|
||||
access_denied
|
||||
return false
|
||||
end
|
||||
|
||||
# overwrite if you want to have special behavior in case the user is not authorized
|
||||
# to access the current operation.
|
||||
# the default action is to redirect to the login screen
|
||||
# example use :
|
||||
# a popup window might just close itself for instance
|
||||
def access_denied
|
||||
redirect_to :controller=>"login", :action =>"login"
|
||||
end
|
||||
|
||||
# store current uri in the session.
|
||||
# we can return to this location by calling return_location
|
||||
def store_location
|
||||
@session['return-to'] = @request.request_uri
|
||||
end
|
||||
|
||||
# move to the last store_location call or to the passed default one
|
||||
def redirect_back_or_default(default)
|
||||
if @session['return-to'].nil?
|
||||
redirect_to default
|
||||
else
|
||||
redirect_to_url @session['return-to']
|
||||
@session['return-to'] = nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
1018
tracks/lib/redcloth.rb
Normal file
1018
tracks/lib/redcloth.rb
Normal file
File diff suppressed because it is too large
Load diff
0
tracks/log.tmpl/apache.log
Executable file
0
tracks/log.tmpl/apache.log
Executable file
0
tracks/log.tmpl/development.log
Executable file
0
tracks/log.tmpl/development.log
Executable file
0
tracks/log.tmpl/production.log
Executable file
0
tracks/log.tmpl/production.log
Executable file
0
tracks/log.tmpl/test.log
Executable file
0
tracks/log.tmpl/test.log
Executable file
29
tracks/public/.htaccess
Normal file
29
tracks/public/.htaccess
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# General Apache options
|
||||
AddHandler fastcgi-script .fcgi
|
||||
AddHandler cgi-script .cgi
|
||||
Options +FollowSymLinks +ExecCGI
|
||||
|
||||
# Make sure that mod_ruby.c has been added and loaded as a module with Apache
|
||||
RewriteEngine On
|
||||
|
||||
# Change extension from .cgi to .fcgi to switch to FCGI and to .rb to switch to mod_ruby
|
||||
RewriteBase /dispatch.cgi
|
||||
|
||||
# Enable this rewrite rule to point to the controller/action that should serve root.
|
||||
# RewriteRule ^$ /controller/action [R]
|
||||
|
||||
# Add missing slash
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)$ /$1/ [R]
|
||||
|
||||
# Default rewriting rules.
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ ?controller=$1&action=$2&id=$3 [QSA,L]
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ ?controller=$1&action=$2 [QSA,L]
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/$ ?controller=$1&action=index [QSA,L]
|
||||
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ ?module=$1&controller=$2&action=$3&id=$4 [QSA,L]
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ ?module=$1&controller=$2&action=$3 [QSA,L]
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/$ ?module=$1&controller=$2&action=index [QSA,L]
|
||||
|
||||
# You can also point these error messages to a controller/action
|
||||
ErrorDocument 500 /500.html
|
||||
ErrorDocument 404 /404.html
|
||||
6
tracks/public/404.html
Normal file
6
tracks/public/404.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<html>
|
||||
<body>
|
||||
<h1>File not found</h1>
|
||||
<p>Change this error message for pages not found in public/404.html</p>
|
||||
</body>
|
||||
</html>
|
||||
6
tracks/public/500.html
Normal file
6
tracks/public/500.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<html>
|
||||
<body>
|
||||
<h1>Application error (Apache)</h1>
|
||||
<p>Change this error message for exceptions thrown outside of an action (like in Dispatcher setups or broken Ruby code) in public/500.html</p>
|
||||
</body>
|
||||
</html>
|
||||
70
tracks/public/_doc/index.html
Normal file
70
tracks/public/_doc/index.html
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Rails: Welcome on board</title>
|
||||
<style>
|
||||
body { background-color: #fff; color: #333; }
|
||||
|
||||
body, p, ol, ul, td {
|
||||
font-family: verdana, arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #eee;
|
||||
padding: 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
a { color: #000; }
|
||||
a:visited { color: #666; }
|
||||
a:hover { color: #fff; background-color:#000; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Congratulations, you've put Ruby on Rails!</h1>
|
||||
|
||||
<p><b>Before you move on</b>, verify that the following conditions have been met:</p>
|
||||
|
||||
<ol>
|
||||
<li>The log directory and the empty log files must be writable to the web server (<code>chmod -R 777 log</code>).
|
||||
<li>
|
||||
The shebang line in the public/dispatch* files must reference your Ruby installation. <br/>
|
||||
You might need to change it to <code>#!/usr/bin/env ruby</code> or point directly at the installation.
|
||||
</li>
|
||||
<li>
|
||||
Rails on Apache needs to have the cgi handler and mod_rewrite enabled. <br/>
|
||||
Somewhere in your httpd.conf, you should have:<br/>
|
||||
<code>AddHandler cgi-script .cgi</code><br/>
|
||||
<code>LoadModule rewrite_module libexec/httpd/mod_rewrite.so</code><br/>
|
||||
<code>AddModule mod_rewrite.c</code>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>Take the following steps to get started:</p>
|
||||
|
||||
<ol>
|
||||
<li>Create empty development and test databases for your application.<br/>
|
||||
<small>Recommendation: Use *_development and *_test names, such as basecamp_development and basecamp_test</small><br/>
|
||||
<small>Warning: Don't point your test database at your development database, it'll destroy the latter on test runs!</small>
|
||||
<li>Edit config/database.yml with your database settings.
|
||||
<li>Create controllers and models using the generator in <code>script/generate</code> <br/>
|
||||
<small>Help: Run the generator with no arguments for documentation</small>
|
||||
<li>See all the tests run by running <code>rake</code>.
|
||||
<li>Develop your Rails application!
|
||||
<li>Setup Apache with <a href="http://www.fastcgi.com">FastCGI</a> (and <a href="http://raa.ruby-lang.org/list.rhtml?name=fcgi">Ruby bindings</a>), if you need better performance
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
Having problems getting up and running? First try debugging it yourself by looking at the log files. <br/>
|
||||
Then try the friendly Rails community <a href="http://www.rubyonrails.org">on the web</a> or <a href="http://www.rubyonrails.org/show/IRC">on IRC</a>
|
||||
(<a href="irc://irc.freenode.net/#rubyonrails">FreeNode#rubyonrails</a>).
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
10
tracks/public/dispatch.cgi
Executable file
10
tracks/public/dispatch.cgi
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/local/bin/ruby
|
||||
|
||||
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
|
||||
|
||||
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
|
||||
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
|
||||
require "dispatcher"
|
||||
|
||||
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) }
|
||||
Dispatcher.dispatch
|
||||
7
tracks/public/dispatch.fcgi
Executable file
7
tracks/public/dispatch.fcgi
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/local/bin/ruby
|
||||
|
||||
require File.dirname(__FILE__) + "/../config/environment"
|
||||
require 'dispatcher'
|
||||
require 'fcgi'
|
||||
|
||||
FCGI.each_cgi { |cgi| Dispatcher.dispatch(cgi) }
|
||||
10
tracks/public/dispatch.rb
Executable file
10
tracks/public/dispatch.rb
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/local/bin/ruby
|
||||
|
||||
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
|
||||
|
||||
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
|
||||
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
|
||||
require "dispatcher"
|
||||
|
||||
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) }
|
||||
Dispatcher.dispatch
|
||||
BIN
tracks/public/images/delete.png
Normal file
BIN
tracks/public/images/delete.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
BIN
tracks/public/images/done.png
Normal file
BIN
tracks/public/images/done.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 905 B |
BIN
tracks/public/images/edit.png
Normal file
BIN
tracks/public/images/edit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3 KiB |
BIN
tracks/public/images/notes.png
Normal file
BIN
tracks/public/images/notes.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
1
tracks/public/index.html
Normal file
1
tracks/public/index.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<html><head><META HTTP-EQUIV="Refresh" CONTENT="0;URL=_doc/index.html"></head></html>
|
||||
13
tracks/public/javascripts/toggle_notes.js
Normal file
13
tracks/public/javascripts/toggle_notes.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
function toggleAll(itemname,state)
|
||||
{
|
||||
tmp = document.getElementsByTagName('div');
|
||||
for (i=0;i<tmp.length;i++)
|
||||
{
|
||||
if (tmp[i].className == itemname) tmp[i].style.display = state;
|
||||
}
|
||||
}
|
||||
|
||||
function toggle(idname)
|
||||
{
|
||||
document.getElementById(idname).style.display = (document.getElementById(idname).style.display == 'none') ? 'block' : 'none';
|
||||
}
|
||||
51
tracks/public/stylesheets/scaffold.css
Normal file
51
tracks/public/stylesheets/scaffold.css
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
body { background-color: #fff; color: #333; }
|
||||
|
||||
body, p, ol, ul, td {
|
||||
font-family: verdana, arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
a { color: #000; }
|
||||
a:visited { color: #666; }
|
||||
a:hover { color: #fff; background-color: #000; }
|
||||
|
||||
h1, h2, h3 { color: #333; font-family: verdana, arial, helvetica, sans-serif; text-align: center; }
|
||||
h1 { font-size: 28px }
|
||||
h2 { font-size: 19px }
|
||||
h3 { font-size: 16px }
|
||||
|
||||
li { margin-bottom: 7px; }
|
||||
|
||||
pre {
|
||||
background-color: #eee;
|
||||
padding: 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#scaffold-main {
|
||||
width: 80%;
|
||||
margin: 10px auto;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
div.form {
|
||||
width: 40%;
|
||||
margin: 100px auto;
|
||||
padding: 10px;
|
||||
border: 1px solid #999;
|
||||
background: #ff9;
|
||||
}
|
||||
|
||||
div.memo {
|
||||
width: 40%;
|
||||
margin: 100px auto;
|
||||
padding: 10px;
|
||||
border: 1px solid #999;
|
||||
background: #ff9;
|
||||
}
|
||||
|
||||
.memo p {
|
||||
background: #ff9;
|
||||
}
|
||||
251
tracks/public/stylesheets/standard.css
Normal file
251
tracks/public/stylesheets/standard.css
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/* Stylesheet for the main listing page */
|
||||
|
||||
body {
|
||||
font-family: "Lucida Grande", Verdana, Geneva, Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
line-height: 19px;
|
||||
padding: 0px 10px;
|
||||
margin: 0px;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
p {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
|
||||
a, a:link, a:active, a:visited {
|
||||
color: #cc3334;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Structural divs */
|
||||
|
||||
#display_box {
|
||||
float: left;
|
||||
width: 450px;
|
||||
margin: 0px 15px 50px 15px;
|
||||
}
|
||||
|
||||
#display_box_projects {
|
||||
float: left;
|
||||
width: 820px;
|
||||
margin: 0px 15px 50px 15px;
|
||||
}
|
||||
|
||||
/* Navigation links at the top */
|
||||
|
||||
#navcontainer {
|
||||
margin: 15px;
|
||||
width: 820px;
|
||||
}
|
||||
|
||||
#navlist {
|
||||
margin: 0;
|
||||
padding: 0 0 20px 10px;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
|
||||
#navlist ul, #navlist li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#navlist a:link, #navlist a:visited {
|
||||
float: left;
|
||||
line-height: 14px;
|
||||
font-weight: bold;
|
||||
margin: 0 10px 4px 10px;
|
||||
text-decoration: none;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#navlist a:link#current, #navlist a:visited#current, #navlist a:hover {
|
||||
border-bottom: 4px solid #000;
|
||||
padding-bottom: 2px;
|
||||
background: transparent;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#navlist a:hover { color: #000; }
|
||||
|
||||
.contexts {
|
||||
padding: 0px 5px 2px 5px;
|
||||
border: 1px solid #999;
|
||||
margin: 0px 0px 15px 0px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.contexts h2 {
|
||||
background: #CCC;
|
||||
padding: 5px;
|
||||
margin-top: 0px;
|
||||
margin-left: -5px;
|
||||
margin-right: -5px;
|
||||
color: #fff;
|
||||
text-shadow: rgba(0,0,0,.4) 0px 2px 5px;
|
||||
}
|
||||
|
||||
h2 a, h2 a:link, h2 a:active, h2 a:visited {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h2 a:hover {
|
||||
color: #cc3334;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#input_box {
|
||||
margin: 20px 50px 20px 490px;
|
||||
padding: 0px 15px 0px 15px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
#input_box h2 {
|
||||
background: #CCC;
|
||||
padding: 5px;
|
||||
margin-top: 0px;
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
color: #fff;
|
||||
text-shadow: rgba(0,0,0,.4) 0px 2px 5px;
|
||||
}
|
||||
|
||||
.box {
|
||||
float: left;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-left: 25px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.tools {
|
||||
margin-left: 25px;
|
||||
width: 40px;
|
||||
border-top: 1px solid #999;
|
||||
}
|
||||
|
||||
#footer {
|
||||
width: 820px;
|
||||
clear: both;
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
background: #CCC;
|
||||
border: 1px solid #999;
|
||||
margin: 0px 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
/* The notes which may be attached to an item */
|
||||
.notes {
|
||||
margin: 5px 20px;
|
||||
padding: 3px;
|
||||
border: 1px solid #F5ED59;
|
||||
background: #FAF6AE;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.notes p, .notes li {
|
||||
padding: 1px 5px;
|
||||
margin: 0px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.notes ul {
|
||||
list-style-type: disc;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.notes ol {
|
||||
list-style-type: decimal;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/* The alert box notifications */
|
||||
.confirmation {
|
||||
margin: 20px 50px 20px 490px;
|
||||
border: 1px solid #007E00;
|
||||
background-color: #c2ffc2;
|
||||
padding: 5px;
|
||||
color: #007E00;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.warning {
|
||||
margin: 20px 50px 20px 490px;
|
||||
border: 1px solid #ED2E38;
|
||||
background-color: #F6979C;
|
||||
padding: 5px;
|
||||
color: #007E00;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Draw attention to some text
|
||||
Same format as traffic lights */
|
||||
.red {
|
||||
color: #fff;
|
||||
background: #f00;
|
||||
padding: 1px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.amber {
|
||||
color: #fff;
|
||||
background: #ff6600;
|
||||
padding: 1px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.green {
|
||||
color: #fff;
|
||||
background: #33cc00;
|
||||
padding: 1px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.grey {
|
||||
color: #fff;
|
||||
background: #999;
|
||||
padding: 1px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/* Shows the number of undone next action */
|
||||
.badge {
|
||||
color: #fff;
|
||||
background: #f00;
|
||||
padding: 5px;
|
||||
font-size: 16px;
|
||||
margin: 10px 10px 0px 0px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin-left: -25px;
|
||||
}
|
||||
|
||||
li {
|
||||
font-size: 1.1em;
|
||||
padding: 3px 0px;
|
||||
}
|
||||
|
||||
td {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.even_row {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.odd_row {
|
||||
background: #cbffff;
|
||||
}
|
||||
4
tracks/script/breakpointer
Executable file
4
tracks/script/breakpointer
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require 'rubygems'
|
||||
require_gem 'rails'
|
||||
require 'breakpoint_client'
|
||||
30
tracks/script/console
Executable file
30
tracks/script/console
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/local/bin/ruby
|
||||
|
||||
if ARGV[0]
|
||||
ENV['RAILS_ENV'] = ARGV[0]
|
||||
puts "Loading environment..."
|
||||
exec "irb -r config/environment.rb -r irb/completion --noinspect"
|
||||
else
|
||||
puts <<-HELP
|
||||
|
||||
NAME
|
||||
console - interact with the domain model through a environment console (on IRB)
|
||||
|
||||
SYNOPSIS
|
||||
console [environment]
|
||||
|
||||
DESCRIPTION
|
||||
Starts an environment console using IRB that lets you manipulate and interrogate
|
||||
the domain model or even trigger controller actions. The database connection and
|
||||
configuration available to the web application is already setup.
|
||||
|
||||
Tab completion is available to see classes and methods on individual objects.
|
||||
|
||||
EXAMPLE
|
||||
console production
|
||||
|
||||
This will initialize the production environment (as setup in config/database.yml
|
||||
and config/environments/production.rb). You would now be ready to start requiring
|
||||
models using require_dependency.
|
||||
HELP
|
||||
end
|
||||
69
tracks/script/generate
Executable file
69
tracks/script/generate
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require File.dirname(__FILE__) + '/../config/environment'
|
||||
require 'rails_generator'
|
||||
|
||||
ARGV.shift unless ARGV.empty? or not ['--help', '-h'].include?(ARGV[0])
|
||||
|
||||
def find_synonyms(word)
|
||||
require 'open-uri'
|
||||
uri = "http://wordnet.princeton.edu/cgi-bin/webwn2.0?stage=2" +
|
||||
"&word=%s&posnumber=1&searchtypenumber=2&senses=&showglosses=1"
|
||||
|
||||
open(uri % word) do |stream|
|
||||
data = stream.read.gsub(" ", " ").gsub("<BR>", "")
|
||||
data.scan(/^Sense \d+\n.+?\n\n/m)
|
||||
end
|
||||
rescue Exception
|
||||
return nil
|
||||
end
|
||||
|
||||
unless ARGV.empty?
|
||||
begin
|
||||
name = ARGV.shift
|
||||
generator = Rails::Generator.instance(name, ARGV)
|
||||
|
||||
if msg = generator.collision_with_builtin? then
|
||||
$stderr.puts msg
|
||||
|
||||
if synonyms = find_synonyms(generator.class_name) then
|
||||
$stderr.puts(
|
||||
"", "Here are a few synonyms from WordNet. Maybe they will help you find an alternative name.",
|
||||
"", synonyms
|
||||
)
|
||||
end
|
||||
else
|
||||
generator.generate
|
||||
end
|
||||
rescue Rails::Generator::UsageError => e
|
||||
puts e.message
|
||||
end
|
||||
else
|
||||
builtin_generators = Rails::Generator.builtin_generators.join(', ')
|
||||
contrib_generators = Rails::Generator.contrib_generators.join(', ')
|
||||
|
||||
$stderr.puts <<end_usage
|
||||
#{$0} generator [args]
|
||||
|
||||
Rails comes with #{builtin_generators} generators.
|
||||
#{$0} controller Login login logout
|
||||
#{$0} model Account
|
||||
#{$0} mailer AccountMailer
|
||||
#{$0} scaffold Account action another_action
|
||||
|
||||
end_usage
|
||||
|
||||
unless contrib_generators.empty?
|
||||
$stderr.puts " Installed generators (in #{RAILS_ROOT}/script/generators):"
|
||||
$stderr.puts " #{contrib_generators}"
|
||||
$stderr.puts
|
||||
end
|
||||
|
||||
$stderr.puts <<end_usage
|
||||
More generators are available at http://rubyonrails.org/show/Generators
|
||||
1. Download, for example, login_generator.tar.gz
|
||||
2. Unzip to directory #{RAILS_ROOT}/script/generators/login
|
||||
3. Generate without args for usage information
|
||||
#{$0} login
|
||||
end_usage
|
||||
exit 0
|
||||
end
|
||||
49
tracks/script/server
Executable file
49
tracks/script/server
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/local/bin/ruby
|
||||
|
||||
require 'webrick'
|
||||
require 'optparse'
|
||||
|
||||
OPTIONS = {
|
||||
:port => 3000,
|
||||
:ip => "127.0.0.1",
|
||||
:environment => "development",
|
||||
:server_root => File.expand_path(File.dirname(__FILE__) + "/../public/"),
|
||||
:server_type => WEBrick::SimpleServer
|
||||
}
|
||||
|
||||
ARGV.options do |opts|
|
||||
script_name = File.basename($0)
|
||||
opts.banner = "Usage: ruby #{script_name} [options]"
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on("-p", "--port=port", Integer,
|
||||
"Runs Rails on the specified port.",
|
||||
"Default: 3000") { |OPTIONS[:port]| }
|
||||
opts.on("-b", "--binding=ip", String,
|
||||
"Binds Rails to the specified ip.",
|
||||
"Default: 127.0.0.1") { |OPTIONS[:ip]| }
|
||||
opts.on("-i", "--index=controller", String,
|
||||
"Specifies an index controller that requests for root will go to (instead of congratulations screen)."
|
||||
) { |OPTIONS[:index_controller]| }
|
||||
opts.on("-e", "--environment=name", String,
|
||||
"Specifies the environment to run this server under (test/development/production).",
|
||||
"Default: development") { |OPTIONS[:environment]| }
|
||||
opts.on("-d", "--daemon",
|
||||
"Make Rails run as a Daemon (only works if fork is available -- meaning on *nix)."
|
||||
) { OPTIONS[:server_type] = WEBrick::Daemon }
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on("-h", "--help",
|
||||
"Show this help message.") { puts opts; exit }
|
||||
|
||||
opts.parse!
|
||||
end
|
||||
|
||||
ENV["RAILS_ENV"] = OPTIONS[:environment]
|
||||
require File.dirname(__FILE__) + "/../config/environment"
|
||||
require 'webrick_server'
|
||||
|
||||
puts "=> Rails application started on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}"
|
||||
DispatchServlet.dispatch(OPTIONS)
|
||||
1
tracks/test/fixtures/contexts.yml
vendored
Normal file
1
tracks/test/fixtures/contexts.yml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
1
tracks/test/fixtures/projects.yml
vendored
Normal file
1
tracks/test/fixtures/projects.yml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
1
tracks/test/fixtures/todos.yml
vendored
Normal file
1
tracks/test/fixtures/todos.yml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
1
tracks/test/fixtures/users.yml
vendored
Normal file
1
tracks/test/fixtures/users.yml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
17
tracks/test/functional/context_controller_test.rb
Normal file
17
tracks/test/functional/context_controller_test.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
require 'context_controller'
|
||||
|
||||
# Re-raise errors caught by the controller.
|
||||
class ContextController; def rescue_action(e) raise e end; end
|
||||
|
||||
class ContextControllerTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@controller = ContextController.new
|
||||
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
17
tracks/test/functional/feed_controller_test.rb
Normal file
17
tracks/test/functional/feed_controller_test.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
require 'feed_controller'
|
||||
|
||||
# Re-raise errors caught by the controller.
|
||||
class FeedController; def rescue_action(e) raise e end; end
|
||||
|
||||
class FeedControllerTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@controller = FeedController.new
|
||||
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
17
tracks/test/functional/login_controller_test.rb
Normal file
17
tracks/test/functional/login_controller_test.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
require 'login_controller'
|
||||
|
||||
# Re-raise errors caught by the controller.
|
||||
class LoginController; def rescue_action(e) raise e end; end
|
||||
|
||||
class LoginControllerTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@controller = LoginController.new
|
||||
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
17
tracks/test/functional/project_controller_test.rb
Normal file
17
tracks/test/functional/project_controller_test.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
require 'project_controller'
|
||||
|
||||
# Re-raise errors caught by the controller.
|
||||
class ProjectController; def rescue_action(e) raise e end; end
|
||||
|
||||
class ProjectControllerTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@controller = ProjectController.new
|
||||
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
17
tracks/test/functional/todo_controller_test.rb
Normal file
17
tracks/test/functional/todo_controller_test.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
require 'todo_controller'
|
||||
|
||||
# Re-raise errors caught by the controller.
|
||||
class TodoController; def rescue_action(e) raise e end; end
|
||||
|
||||
class TodoControllerTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@controller = TodoController.new
|
||||
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
14
tracks/test/test_helper.rb
Normal file
14
tracks/test/test_helper.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
ENV["RAILS_ENV"] ||= "test"
|
||||
require File.dirname(__FILE__) + "/../config/environment"
|
||||
require 'application'
|
||||
|
||||
require 'test/unit'
|
||||
require 'active_record/fixtures'
|
||||
require 'action_controller/test_process'
|
||||
require 'breakpoint'
|
||||
|
||||
def create_fixtures(*table_names)
|
||||
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures", table_names)
|
||||
end
|
||||
|
||||
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
||||
10
tracks/test/unit/context_test.rb
Normal file
10
tracks/test/unit/context_test.rb
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class ContextTest < Test::Unit::TestCase
|
||||
fixtures :contexts
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
10
tracks/test/unit/project_test.rb
Normal file
10
tracks/test/unit/project_test.rb
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class ProjectTest < Test::Unit::TestCase
|
||||
fixtures :projects
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
10
tracks/test/unit/todo_test.rb
Normal file
10
tracks/test/unit/todo_test.rb
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class TodoTest < Test::Unit::TestCase
|
||||
fixtures :todos
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
10
tracks/test/unit/user_test.rb
Normal file
10
tracks/test/unit/user_test.rb
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class UserTest < Test::Unit::TestCase
|
||||
fixtures :users
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue