--- /dev/null
+code/wfpl
+images
+*.tgz
+run.php
+style*.css
+w
require_once('code/db_connect.php');
require_once('code/wfpl/session_messages.php');
+
+function cms_get() {
+ if(logged_in()) {
+ return array('logout_bar' => '<div style="text-align: right"><a href="logout">Log out</a></div>');
+ }
+ return false;
+}
+
+function logged_in_as_admin() {
+ if(!isset($GLOBALS['logged_in_as_admin'])) {
+ $GLOBALS['logged_in_as_admin'] = (logged_in() == 1); # logged_in() returns id. id #1 is admin
+ }
+ return $GLOBALS['logged_in_as_admin'];
+}
+
+function logged_in_as_contractor() {
+ return logged_in_as_admin();
+}
case TASK_NEEDS_CLARIFICATION:
return "needs clarification";
case TASK_NEEDS_QUOTE:
- return "waiting for price from Jason";
+ return "to be priced";
case TASK_NEEDS_GO_AHEAD:
- return "waiting for you to approve price";
+ return "waiting for you to approve the price";
case TASK_QUEUED:
return "queued";
case TASK_WORKING:
return "work in progress";
case TASK_BUG:
- return "investigation in progress";
+ return "to be investigated";
case TASK_NEEDS_TESTING:
return "needs testing";
case TASK_FINISHED:
<body>
<!--~main_body start~-->
- <h2>Progress</h2>
+ <h2>Progress Manager</h2>
- <p>This page is for commissioning Jason Woofenden, working out the details of what is to be done and the cost, and managing schedules and priorities.</p>
+ <p>This page is for commissioning Jason Woofenden, working out the details of the tasks, costs and priorities.</p>
<p><a href="tasks?tasks_new=1">Commission a new feature/update</a> • <a href="tasks?tasks_new_bug=1">Report a problem</a><!-- • <a href="pay">Pay Jason</a>--></p>
function index_main() {
if(!logged_in()) {
- return './login';
+ return 'login';
}
$ret = _index_main();
if($ret) {
tem_show('main_body');
}
-function task_summary($tem_prefix, $where_clause) {
- $rows = db_get_rows('tasks', 'id,price,title,state', $where_clause);
+# pass multiple argumens for where-clause and printf-args just like db_get_rows()
+function task_summary($tem_prefix, $where_clause/*, ... */) {
+ $args = func_get_args();
+ $args = array_slice($args, 1);
+ array_unshift($args, 'tasks', 'id,price,title,state,client_id');
+ print_r($args);
+ $rows = call_user_func_array('db_get_rows', $args);
+ #$rows = db_get_rows('tasks', 'id,price,title,state,client_id', $where_clause);
if($rows) {
$total = 0.0;
foreach($rows as $row) {
- list($id, $price, $title, $state) = $row;
+ list($id, $price, $title, $state, $client_id) = $row;
tem_set('task_id', $id);
tem_set('task_title', $title);
tem_set('task_price', $price);
tem_set('task_state', task_state_pretty($state));
+ if(logged_in_as_contractor()) {
+ tem_set('client', db_get_value('people', 'name', 'where id=%i', $client_id));
+ }
tem_show($tem_prefix . '_row');
$total += $price;
}
}
function _index_main() {
- task_summary('needs_attention', 'where state=' . TASK_DRAFT . ' || state=' . TASK_NEEDS_CLARIFICATION . ' || state=' . TASK_NEEDS_GO_AHEAD . ' || state=' . TASK_NEEDS_TESTING . ' order by id');
- task_summary('queue', 'where state=' . TASK_QUEUED . ' order by ord');
- task_summary('jason', 'where state=' . TASK_NEEDS_QUOTE . ' || state=' . TASK_WORKING . ' || state=' . TASK_BUG . ' order by id desc');
- #task_summary('jason_pricing', 'where state=' . TASK_NEEDS_QUOTE . ' order by id desc');
- #task_summary('jason_working', 'where state=' . TASK_WORKING . ' order by id desc');
- task_summary('finished_unpaid', 'where state=' . TASK_FINISHED . ' && paid = 0 order by id desc');
- task_summary('finished_paid', 'where state=' . TASK_FINISHED . ' && paid = 1 order by id desc');
+ $client_id = logged_in();
+ if(logged_in_as_contractor()) {
+ task_summary('needs_attention', 'where state=%i || state=%i || state=%i order by id desc', TASK_NEEDS_QUOTE, TASK_WORKING, TASK_BUG);
+ task_summary('finished_unpaid', 'where state=%i && paid = 0 order by id desc', TASK_FINISHED);
+ task_summary('finished_paid', 'where state=%i && paid = 1 order by id desc', TASK_FINISHED);
+ } else {
+ task_summary('needs_attention', 'where state=' . TASK_DRAFT . ' || state=' . TASK_NEEDS_CLARIFICATION . ' || state=' . TASK_NEEDS_GO_AHEAD . ' || state=' . TASK_NEEDS_TESTING . ' order by id');
+ task_summary('queue', 'where state=' . TASK_QUEUED . " && client_id=$client_id order by ord");
+ task_summary('jason', 'where state=' . TASK_NEEDS_QUOTE . ' || state=' . TASK_WORKING . ' || state=' . TASK_BUG . ' order by id desc');
+ #task_summary('jason_pricing', 'where state=' . TASK_NEEDS_QUOTE . ' order by id desc');
+ #task_summary('jason_working', 'where state=' . TASK_WORKING . ' order by id desc');
+ task_summary('finished_unpaid', 'where state=' . TASK_FINISHED . ' && paid = 0 order by id desc');
+ task_summary('finished_paid', 'where state=' . TASK_FINISHED . ' && paid = 1 order by id desc');
+ }
return;
}
if(isset($_REQUEST['username'])) {
list($username, $password, $url) = login_get_fields();
- if($username == 'test' && $password == 'test') {
- message("Logged in successfully.");
- session_new();
- session_set('auth_username', "admin:$id");
- if($url) {
- return $url;
- } else {
- return './';
+ $row = db_get_row('people', 'id,password', 'where username=%"', $username);
+
+ if($row) {
+ list($id, $password_hash) = $row;
+
+ if($password_hash && check_password($password_hash, $password)) {
+ message("Logged in successfully.");
+ session_new();
+ session_set('auth_username', "$id");
+ if($url) {
+ return $url;
+ } else {
+ return './';
+ }
}
}
--- /dev/null
+<?php
+
+function logout_main() {
+ kill_session();
+ session_new();
+ message('Logged out');
+ return './';
+}
--- /dev/null
+<!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">
+<head>
+ <title></title>
+</head>
+
+<body>
+<!--~main_body start~-->
+ <h2>Narrative Example</h2>
+
+ <p>When you <a href="./">commission Jason Woofenden</a> you are asked to write about your change/addition in the form of a first-person narrative. In this narrative you write as if the change/addition you would like has already been implemented. You write the specifics of what you do and what you see as a result.</p>
+ <p>Here is an example of a narrative for a new page:</p>
+
+ <p class="boxed">I go to my home page, (or any other page on my site) and I click a link labeled "Contact Us" which is just below the "About Us" link on the left. Then I see a page with a headline "Contact Us" and a form with these fields: "Name", "E-mail", "Comments" and a button "Send". When I click "Send", all information entered is e-mailed to foo@example.com and I see a page with the headline "Thank You" and this paragraph: "Thank you for your interest. We can usually reply within one business day."</p>
+
+ <p>After Jason makes the changes, you can verify that they are complete by following the steps in the narrative and making sure you can see everything it describes.</p>
+<!--~end~-->
+</body>
+</html>
--- /dev/null
+<!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">
+<head>
+ <title>people entry</title>
+ <link rel="stylesheet" href="style.css" type="text/css" />
+</head>
+
+<body>
+ <!--~main_body start~-->
+
+ <!--~message_container start~-->
+ <div style="border: 2px solid red; background: #fbb; padding: 5px; margin: 20px 0px">
+ <!--~message_box start~-->
+ <!--~message_divider start~-->
+ <hr />
+ <!--~end~-->
+ <p style="font-size: 120%; padding: 5px; margin: 0px">~message_text.html~</p>
+ <!--~end~-->
+ </div>
+ <!--~end~-->
+
+<!--~form start~-->
+ <h2><!--~new_msg start~-->Add a new entry<!--~end~--><!--~edit_msg start~-->Edit entry "~username.html~"<!--~end~--></h2>
+
+ <form action="people" method="post"><!--~editing start~--><input type="hidden" name="people_edit_id" value="~people_edit_id.attr~" /><!--~end~-->
+ <table cellspacing="0" cellpadding="4" border="0" summary="">
+
+ <tr><td class="caption">Username: </td><td class="field"><input type="text" name="username" value="~username.attr~" /></td></tr>
+
+ <tr><td class="caption">Password: </td><td class="field"><input type="text" name="password" value="~password.attr~" /></td></tr>
+
+ <tr><td class="caption">Name: </td><td class="field"><input type="text" name="name" value="~name.attr~" /></td></tr>
+
+ <tr><td class="caption">Privs: </td><td class="field"><input type="text" name="privs" value="~privs.attr~" /></td></tr>
+
+ <tr><td class="caption">Balance: </td><td class="field"><input type="text" name="balance" value="~balance.attr~" /></td></tr>
+
+ <tr><td class="submit_row" colspan="2"><input type="submit" name="save" value="Save" /></td></tr>
+ </table>
+ </form>
+<!--~end~-->
+<!--~listings start~-->
+ <h2>people Listing</h2>
+
+ <!--~populated_listing start~-->
+ <p><a href="people.html?people_new=1">[Add a new record]</a></p>
+
+ <table cellspacing="0" cellpadding="4" border="1" summary=""><!--~listing_row start~-->
+ <tr><td class="listing"><a href="people.html?people_edit_id=~id~">~username.html~</a></td><td><a href="people.html?people_delete_id=~id~" onclick="return confirm('Permanently delete?')">[delete this record]</a></td></tr><!--~end~-->
+
+ </table>
+ <!--~end~-->
+ <!--~empty_listing start~-->
+ <p>No ~field_plural.html~ in database.</p>
+ <!--~end~-->
+
+ <p><a href="people.html?people_new=1">[Add a new record]</a></p>
+<!--~end~-->
+
+<!--~end~-->
+</body>
+</html>
--- /dev/null
+<?php
+
+# This form requires wfpl. See: http://jasonwoof.org/wfpl
+
+# This form was initially auto-generated. If you would like to alter the
+# parameters and generate a new one try this URL:
+#
+# http://jasonwoof.com/metaform/?form_name=people&opt_email=No&opt_db=Yes&opt_listing=Yes&opt_http_pass=No&fields=username+textbox%0D%0Apassword+textbox%0D%0Aname+textbox%0D%0Aprivs+int%0D%0Abalance+decimal&edit=yes
+
+
+# SETUP
+
+# To save results to a database, you'll need to create the people table
+# (the file people.sql should help with this), and create the file
+# 'code/db_connect.php' which calls db_connect() see:
+# code/wfpl/examples/db_connect.php
+#
+# if you rename any of the database fields, you'll need to update this:
+
+define('PEOPLE_DB_FIELDS', 'username,password,name,privs,balance');
+
+
+require_once('code/wfpl/template.php');
+require_once('code/wfpl/format.php');
+require_once('code/wfpl/messages.php');
+require_once('code/wfpl/email.php');
+require_once('code/db_connect.php');
+
+function people_get_fields() {
+ $username = format_oneline($_REQUEST['username']);
+ $password = format_oneline($_REQUEST['password']);
+ $name = format_oneline($_REQUEST['name']);
+ $privs = format_int($_REQUEST['privs']);
+ $balance = format_decimal($_REQUEST['balance']);
+
+ people_tem_sets($username, $password, $name, $privs, $balance);
+
+ return array($username, $password, $name, $privs, $balance);
+}
+
+function people_tem_sets($username, $password, $name, $privs, $balance) {
+ tem_set('username', $username);
+ tem_set('password', $password);
+ tem_set('name', $name);
+ tem_set('privs', $privs);
+ tem_set('balance', $balance);
+}
+
+# You may pass a "where clause" for the db query.
+function people_display_listing($where = 'order by username limit 100') {
+ $rows = db_get_rows('people', 'id,username', $where);
+ if($rows == false || count($rows) == 0) {
+ tem_show('empty_listing');
+ tem_show('listings');
+ return false;
+ }
+
+ foreach($rows as $row) {
+ list($id, $username) = $row;
+ tem_set('id', $id);
+ if($username == '') {
+ $username = '--';
+ }
+ tem_set('username', $username);
+ tem_show('listing_row');
+ }
+ tem_show('populated_listing');
+ tem_show('listings');
+ return true;
+}
+
+function people_main() {
+ if(logged_in() != 1) { # FIXME get more sophisticated than first person in database is admin
+ $GLOBALS['url'] = this_url();
+ message('You must be logged in as an administrator to access that function');
+ return 'login';
+ }
+
+ $ret = _people_main();
+ if($ret) {
+ return $ret;
+ }
+ tem_show('main_body');
+}
+
+function _people_main() {
+ $edit_id = format_int($_REQUEST['people_edit_id']);
+ unset($_REQUEST['people_edit_id']);
+ if($edit_id) {
+ # add hidden field for database id of row we're editing
+ tem_set('people_edit_id', $edit_id);
+ tem_show('editing');
+ }
+
+ $delete_id = format_int($_REQUEST['people_delete_id']);
+ unset($_REQUEST['people_delete_id']);
+ if($delete_id) {
+ db_delete('people', 'where id=%i', $delete_id);
+ message('Entry deleted.');
+
+ return './people.html';
+ }
+
+ if(!$edit_id) {
+ if(!isset($_REQUEST['people_new']) && !isset($_REQUEST['username'])) {
+ people_display_listing();
+ return;
+ }
+
+ tem_show('new_msg');
+ }
+
+ if(isset($_REQUEST['username'])) {
+ list($username, $password, $name, $privs, $balance) = people_get_fields();
+
+ if("you're happy with the POSTed values") {
+ if(strlen($password) == 35 && substr($password, 32, 1) == ':') {
+ $password_hash = $password; # so we can edit a record, and leave the password be
+ } else {
+ $password_hash = encrypt_password($password);
+ }
+
+ if($edit_id) {
+ db_update('people', PEOPLE_DB_FIELDS, $username, $password_hash, $name, $privs, $balance, 'where id=%i', $edit_id);
+ message('Entry updated.');
+ } else {
+ db_insert('people', PEOPLE_DB_FIELDS, $username, $password_hash, $name, $privs, $balance);
+ message('Entry saved.');
+ }
+ if($error !== true) {
+ return './people';
+ }
+ }
+ # otherwise, we display the form again. people_get_fields() has
+ # already put the posted values back into the template engine, so they will
+ # show up in the form fields. You should add some message asking people to
+ # fix their entry in whatever way you require.
+ } elseif($edit_id) {
+ # we've recieved an edit id, but no data. So we grab the values to be edited from the database
+ list($username, $password, $name, $privs, $balance) = db_get_row('people', PEOPLE_DB_FIELDS, 'where id=%i', $edit_id);
+ people_tem_sets($username, $password, $name, $privs, $balance);
+ } else {
+ # form not submitted, you can set default values like so:
+ #tem_set('username', 'Yes');
+ }
+
+ # this has to be later in the file because it requres that username be set already
+ if($edit_id) {
+ tem_show('edit_msg');
+ }
+
+ tem_show('form');
+}
+
+?>
<body>
<!--~main_body start~-->
-<!--~form start~-->
- <h3><!--~new_msg start~-->Add a new task<!--~end~--><!--~edit_msg start~-->Edit task #~tasks_edit_id~ "~title.html~"<!--~end~--></h3>
+<!--~display_body start~-->
+ <h3><!--~normal_title start~-->Task #~task_id~<!--~end~--><!--~bug_title start~-->Problem Report<!--~end~--> "~title.html~"</h3>
+
+ <p><strong>Title</strong>: ~title.html~</p>
+
+ <p><strong>Status</strong>: ~state.html~</p>
+
+ <p><strong>URL</strong>: <a target="_new" href="~url.attr~">~url.html~</a></p>
+
+ <p style="padding-left: 20px; text-indent: -20px"><strong>Narrative</strong>:<br />
+ ~description.htmlbrtab~</p>
+
+ <p><a href="./">Back</a></p>
+<!--~end~-->
+
+<!--~edit_body start~-->
+ <h3><!--~bug_msg start~-->Report a problem<!--~end~--><!--~new_msg start~-->Add a new task<!--~end~--><!--~edit_msg start~-->Edit task #~tasks_edit_id~ "~title.html~"<!--~end~--></h3>
<form action="tasks" method="post"><!--~editing start~--><input type="hidden" name="tasks_edit_id" value="~tasks_edit_id.attr~" /><!--~end~-->
<table cellspacing="0" cellpadding="4" border="0" summary="">
- <tr><td class="caption">Title: </td><td class="field"><input type="text" name="title" value="~title.attr~" /></td></tr>
+ <tr><td class="caption">Title: </td><td class="field"><input type="text" size="40" name="title" value="~title.attr~" /></td></tr>
+
+ <tr><td class="caption">URL: </td><td class="field"><input type="text" size="40" name="url" value="~url.attr~" /></td></tr>
- <tr><td class="caption">Url: </td><td class="field"><input type="text" name="url" value="~url.attr~" /></td></tr>
- <tr><td class="caption">Description: </td><td class="field"><textarea rows="9" cols="22" name="description">~description.html~</textarea></td></tr>
+ <tr><td colspan="2"><!--~normal_instructions start~-->Below, write as if the change/addition you would like has already been implemented. Write a first-person narrative with the specifics of what you do and what you see as a result. <a target="_new" href="narrative_example">See an example</a>.<!--~end~--><!--~bug_instructions start~-->Below, describe in detail 1) what you do, 2) what you expect to see, 3) what you see instead<!--~end~--></td></tr>
+ <tr><td colspan="2" class="field"><textarea rows="20" cols="50" name="description">~description.html~</textarea></td></tr>
<!--~normal_submits start~-->
<tr><td class="submit_row" colspan="2"><input type="submit" name="save" value="Save and Request Price" /></td></tr>
<tr><td class="submit_row" colspan="2"><input type="submit" name="save_draft" value="Save Draft" /></td></tr>
<!--~end~-->
</table>
</form>
-<!--~end~-->
-<!--~thankyou start~-->
- <p>Thank you for taking the time to fill out this form.</p>
+ <p><a href="./">Cancel</a></p>
<!--~end~-->
+
<!--~end~-->
</body>
</html>
require_once('code/wfpl/email.php');
require_once('code/db_connect.php');
+# replace every character in $str with " "
+function tonbsp($matches) {
+ return str_repeat(' ', strlen($matches[0]) * 2);
+}
+
+# encode as html, make it display newlines and leading spaces
+function enc_htmlbrtab($str) {
+ $str = enc_htmlbr($str);
+ $str = preg_replace_callback("|^ *|m", tonbsp, $str);
+ return $str;
+}
+
function tasks_get_fields() {
$title = format_oneline($_REQUEST['title']);
$url = format_oneline($_REQUEST['url']);
}
function tasks_main() {
- $ret = _tasks_main();
- if($ret) {
- return $ret;
+ if(!logged_in()) {
+ $GLOBALS['url'] = this_url();
+ return 'login';
}
+
+ if(isset($_REQUEST['tasks_id'])) {
+ $ret = tasks_display_main();
+ if($ret) {
+ return $ret;
+ }
+ tem_show('display_body');
+ } else {
+ $ret = tasks_edit_main();
+ if($ret) {
+ return $ret;
+ }
+ tem_show('edit_body');
+ }
+
tem_show('main_body');
}
-function _tasks_main() {
+function tasks_display_main() {
+ $task_id = format_int($_REQUEST['tasks_id']);;
+ $row = db_get_row('tasks', 'title,url,description,state', 'where id=%i', $task_id);
+ if($row) {
+ list($title, $url, $description, $state) = $row;
+ tem_set('task_id', $task_id);
+ tem_set('title', $title);
+ tem_set('url', $url);
+ tem_set('description', $description);
+ tem_set('state', task_state_pretty($state));
+ if($state == TASK_BUG) {
+ tem_show('bug_title');
+ } else {
+ tem_show('normal_title');
+ }
+ } else {
+ message("Task #$task_id not found");
+ return './';
+ }
+}
+
+function tasks_edit_main() {
+ $state = TASK_DRAFT; # will be overwritten
$edit_id = format_int($_REQUEST['tasks_edit_id']);
unset($_REQUEST['tasks_edit_id']);
if($edit_id) {
# add hidden field for database id of row we're editing
tem_set('tasks_edit_id', $edit_id);
tem_show('editing');
+
+ $state = db_get_value('tasks', 'state', 'where id=%i', $edit_id);
}
if(isset($_REQUEST['tasks_new_bug'])) {
tem_show('bug_submit');
+ $state = TASK_BUG;
} else {
tem_show('normal_submits');
}
+ if($state == TASK_BUG) {
+ tem_show('bug_instructions');
+ } else {
+ tem_show('normal_instructions');
+ }
+
$delete_id = format_int($_REQUEST['tasks_delete_id']);
unset($_REQUEST['tasks_delete_id']);
if($delete_id) {
return './tasks.html';
}
- if(!$edit_id) {
- tem_show('new_msg');
- }
-
if(isset($_REQUEST['title'])) {
list($title, $url, $description) = tasks_get_fields();
# this has to be later in the file because it requres that client_id be set already
if($edit_id) {
tem_show('edit_msg');
+ } elseif($state == TASK_BUG) {
+ tem_show('bug_msg');
+ } else {
+ tem_show('new_msg');
}
-
- tem_show('form');
}
?>
<p id="logo"></p>
<div id="body" class="~basename~_body">
+ <!--~logout_bar~-->
<!--~message_container start~-->
<div style="border: 2px solid red; background: #fbb; padding: 5px; margin: 20px 0px">
<!--~message_box start~-->