From: moodler Date: Thu, 28 Sep 2006 06:41:07 +0000 (+0000) Subject: Started out fixing MDL-6624 and it turned into a fairly major cleanup X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=77c645df2875ab5fb3274bc2236611d6e2e96627;p=moodle.git Started out fixing MDL-6624 and it turned into a fairly major cleanup of the participant listing. I think it's a lot better now. Bulk messaging fixed too, and is controlled by a new capability moodle/course:bulkmessaging --- diff --git a/lib/db/access.php b/lib/db/access.php index bdd68b7347..f93a776b69 100644 --- a/lib/db/access.php +++ b/lib/db/access.php @@ -553,6 +553,22 @@ $moodle_capabilities = array( ) ), + 'moodle/course:bulkmessaging' => array( + + 'riskbitmask' => RISK_SPAM, + + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'legacy' => array( + 'guest' => CAP_PREVENT, + 'student' => CAP_PREVENT, + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'coursecreator' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ), + 'moodle/course:viewhiddenuserfields' => array( 'riskbitmask' => RISK_PERSONAL, diff --git a/user/index.php b/user/index.php index 3e558e3cc5..6bcc9d67a4 100644 --- a/user/index.php +++ b/user/index.php @@ -14,7 +14,6 @@ $page = optional_param('page', 0, PARAM_INT); // which page to show $perpage = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT); // how many per page $mode = optional_param('mode', NULL); // '0' for less details, '1' for more - $showteachers = optional_param('teachers', 1, PARAM_INT); // do we want to see the teacher list? $accesssince = optional_param('accesssince',0,PARAM_INT); // filter by last access. -1 = never $search = optional_param('search','',PARAM_CLEAN); $roleid = optional_param('roleid', 0, PARAM_INT); // optional roleid @@ -22,11 +21,8 @@ $contextid = optional_param('contextid', 0, PARAM_INT); // one of this or $courseid = optional_param('id', 0, PARAM_INT); // this are required - $showteachers = $showteachers && empty($search); // if we're searching, we just want students. - if ($contextid) { if (! $context = get_context_instance_by_id($contextid)) { - error("Context ID is incorrect"); } if (! $course = get_record('course', 'id', $context->instanceid)) { @@ -71,11 +67,7 @@ add_to_log($course->id, 'user', 'view all', 'index.php?id='.$course->id, ''); - $isteacher = isteacher($course->id); - - if (empty($isteacher)) { - $search = false; - } + $bulkoperations = has_capability('moodle/course:bulkmessaging', $context); $countries = get_list_of_countries(); @@ -118,7 +110,7 @@ } // Should use this variable so that we don't break stuff every time a variable is added or changed. - $baseurl = $CFG->wwwroot.'/user/index.php?contextid='.$context->id.'&roleid='.$roleid.'&id='.$course->id.'&group='.$currentgroup.'&perpage='.$perpage.'&teachers='.$showteachers.'&accesssince='.$accesssince.'&search='.$search; + $baseurl = $CFG->wwwroot.'/user/index.php?contextid='.$context->id.'&roleid='.$roleid.'&id='.$course->id.'&group='.$currentgroup.'&perpage='.$perpage.'&accesssince='.$accesssince.'&search='.$search; /// Print headers @@ -170,7 +162,7 @@ foreach ($mycourses as $mycourse) { $courselist[$mycourse->id] = $mycourse->shortname; } - popup_form($CFG->wwwroot.'/user/index.php?contextid='.$context->id.'&roleid='.$roleid.'&id=', + popup_form($CFG->wwwroot.'/user/index.php?contextid='.$context->id.'&roleid='.$roleid.'&sifirst=&silast=&id=', $courselist, 'courseform',$course->id); echo ''; } @@ -183,52 +175,51 @@ } } - if (!empty($isteacher)) { - // get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far. - // this might not work anymore because you always going to get yourself as the most recent entry? added $USER!=$user ch - $minlastaccess = get_field_sql('SELECT min(timeaccess) FROM '.$CFG->prefix.'user_lastaccess WHERE courseid = '.$course->id.' AND timeaccess != 0 AND userid!='.$USER->id); - $lastaccess0exists = record_exists('user_lastaccess','courseid',$course->id,'timeaccess',0); - $now = usergetmidnight(time()); - $timeaccess = array(); - - // makes sense for this to go first. - $timeoptions[0] = get_string('selectperiod'); - - // days - for ($i = 1; $i < 7; $i++) { - if (strtotime('-'.$i.' days',$now) >= $minlastaccess) { - $timeoptions[strtotime('-'.$i.' days',$now)] = get_string('numdays','moodle',$i); - } - } - // weeks - for ($i = 1; $i < 10; $i++) { - if (strtotime('-'.$i.' weeks',$now) >= $minlastaccess) { - $timeoptions[strtotime('-'.$i.' weeks',$now)] = get_string('numweeks','moodle',$i); - } - } - // months - for ($i = 2; $i < 12; $i++) { - if (strtotime('-'.$i.' months',$now) >= $minlastaccess) { - $timeoptions[strtotime('-'.$i.' months',$now)] = get_string('nummonths','moodle',$i); - } + // get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far. + // this might not work anymore because you always going to get yourself as the most recent entry? added $USER!=$user ch + $minlastaccess = get_field_sql('SELECT min(timeaccess) FROM '.$CFG->prefix.'user_lastaccess WHERE courseid = '.$course->id.' AND timeaccess != 0 AND userid!='.$USER->id); + $lastaccess0exists = record_exists('user_lastaccess','courseid',$course->id,'timeaccess',0); + $now = usergetmidnight(time()); + $timeaccess = array(); + + // makes sense for this to go first. + $timeoptions[0] = get_string('selectperiod'); + + // days + for ($i = 1; $i < 7; $i++) { + if (strtotime('-'.$i.' days',$now) >= $minlastaccess) { + $timeoptions[strtotime('-'.$i.' days',$now)] = get_string('numdays','moodle',$i); } - // try a year - if (strtotime('-1 year',$now) >= $minlastaccess) { - $timeoptions[strtotime('-1 year',$now)] = get_string('lastyear'); + } + // weeks + for ($i = 1; $i < 10; $i++) { + if (strtotime('-'.$i.' weeks',$now) >= $minlastaccess) { + $timeoptions[strtotime('-'.$i.' weeks',$now)] = get_string('numweeks','moodle',$i); } - - if (!empty($lastaccess0exists)) { - $timeoptions[-1] = get_string('never'); - } - - if (count($timeoptions) > 1) { - echo ''; - echo get_string('usersnoaccesssince').': '; - $baseurl = preg_replace('/&accesssince='.$accesssince.'/','',$baseurl); - echo popup_form($baseurl.'&accesssince=',$timeoptions,'timeoptions',$accesssince,'','','',true); - echo ''; + } + // months + for ($i = 2; $i < 12; $i++) { + if (strtotime('-'.$i.' months',$now) >= $minlastaccess) { + $timeoptions[strtotime('-'.$i.' months',$now)] = get_string('nummonths','moodle',$i); } } + // try a year + if (strtotime('-1 year',$now) >= $minlastaccess) { + $timeoptions[strtotime('-1 year',$now)] = get_string('lastyear'); + } + + if (!empty($lastaccess0exists)) { + $timeoptions[-1] = get_string('never'); + } + + if (count($timeoptions) > 1) { + echo ''; + echo get_string('usersnoaccesssince').': '; + $baseurl = preg_replace('/&accesssince='.$accesssince.'/','',$baseurl); + echo popup_form($baseurl.'&accesssince=',$timeoptions,'timeoptions',$accesssince,'','','',true); + echo ''; + } + echo ''; echo get_string('userlist').': '; @@ -264,122 +255,127 @@ } -/// Define a table showing a list of users in the current role. + /// Define a table showing a list of users in the current role selection + + $tablecolumns = array('picture', 'fullname'); + $tableheaders = array('', get_string('fullname')); + if (!isset($hiddenfields['city'])) { + $tablecolumns[] = 'city'; + $tableheaders[] = get_string('city'); + } + if (!isset($hiddenfields['country'])) { + $tablecolumns[] = 'country'; + $tableheaders[] = get_string('country'); + } + if (!isset($hiddenfields['lastaccess'])) { + $tablecolumns[] = 'lastaccess'; + $tableheaders[] = get_string('lastaccess'); + } + + if ($course->enrolperiod) { + $tablecolumns[] = 'timeend'; + $tableheaders[] = get_string('enrolmentend'); + } + + if ($bulkoperations) { + $tablecolumns[] = ''; + $tableheaders[] = get_string('select'); + } + + $table = new flexible_table('user-index-students-'.$course->id); + + $table->define_columns($tablecolumns); + $table->define_headers($tableheaders); + $table->define_baseurl($baseurl); + + $table->sortable(true, 'lastaccess', SORT_DESC); + + $table->set_attribute('cellspacing', '0'); + $table->set_attribute('id', 'students'); + $table->set_attribute('class', 'generaltable generalbox'); + + $table->set_control_variables(array( + TABLE_VAR_SORT => 'ssort', + TABLE_VAR_HIDE => 'shide', + TABLE_VAR_SHOW => 'sshow', + TABLE_VAR_IFIRST => 'sifirst', + TABLE_VAR_ILAST => 'silast', + TABLE_VAR_PAGE => 'spage' + )); + $table->setup(); + + + // we are looking for all users with this role assigned in this context or higher + if ($usercontexts = get_parent_contexts($context)) { + $listofcontexts = '('.implode(',', $usercontexts).')'; + } else { + $sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID); + $listofcontexts = '('.$sitecontext->id.')'; // must be site + } if ($roleid) { - $tablecolumns = array('picture', 'fullname'); - $tableheaders = array('', get_string('fullname')); - if (!isset($hiddenfields['city'])) { - $tablecolumns[] = 'city'; - $tableheaders[] = get_string('city'); - } - if (!isset($hiddenfields['country'])) { - $tablecolumns[] = 'country'; - $tableheaders[] = get_string('country'); - } - if (!isset($hiddenfields['lastaccess'])) { - $tablecolumns[] = 'lastaccess'; - $tableheaders[] = get_string('lastaccess'); - } - - if ($course->enrolperiod) { - $tablecolumns[] = 'timeend'; - $tableheaders[] = get_string('enrolmentend'); - } - - if ($isteacher) { - $tablecolumns[] = ''; - $tableheaders[] = get_string('select'); - } - - $table = new flexible_table('user-index-students-'.$course->id); - - $table->define_columns($tablecolumns); - $table->define_headers($tableheaders); - $table->define_baseurl($baseurl); - - $table->sortable(true, 'lastaccess', SORT_DESC); - - $table->set_attribute('cellspacing', '0'); - $table->set_attribute('id', 'students'); - $table->set_attribute('class', 'generaltable generalbox'); - - $table->set_control_variables(array( - TABLE_VAR_SORT => 'ssort', - TABLE_VAR_HIDE => 'shide', - TABLE_VAR_SHOW => 'sshow', - TABLE_VAR_IFIRST => 'sifirst', - TABLE_VAR_ILAST => 'silast', - TABLE_VAR_PAGE => 'spage' - )); - $table->setup(); - - - // we are looking for all users with this role assigned in this context or higher - if ($usercontexts = get_parent_contexts($context)) { - $listofcontexts = '('.implode(',', $usercontexts).')'; - } else { - $sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID); - $listofcontexts = '('.$sitecontext->id.')'; // must be site - } - $select = 'SELECT u.id, u.username, u.firstname, u.lastname, u.email, u.city, u.country, - u.picture, u.lang, u.timezone, u.emailstop, u.maildisplay, ul.timeaccess AS lastaccess '; // s.lastaccess - //$select .= $course->enrolperiod?', s.timeend ':''; - $from = "FROM {$CFG->prefix}user u INNER JOIN - {$CFG->prefix}role_assignments r on u.id=r.userid LEFT OUTER JOIN - {$CFG->prefix}user_lastaccess ul on r.userid=ul.userid "; - $where = "WHERE (r.contextid = $context->id OR r.contextid in $listofcontexts) - AND u.deleted = 0 - AND r.roleid = $roleid - AND (ul.courseid = $course->id OR ul.courseid IS NULL) - AND u.username <> 'guest' "; + $selectrole = " AND r.roleid = $roleid "; + } else { + $selectrole = " "; + } + $select = 'SELECT u.id, u.username, u.firstname, u.lastname, u.email, u.city, u.country, + u.picture, u.lang, u.timezone, u.emailstop, u.maildisplay, ul.timeaccess AS lastaccess '; // s.lastaccess + //$select .= $course->enrolperiod?', s.timeend ':''; + $from = "FROM {$CFG->prefix}user u INNER JOIN + {$CFG->prefix}role_assignments r on u.id=r.userid LEFT OUTER JOIN + {$CFG->prefix}user_lastaccess ul on r.userid=ul.userid "; + $where = "WHERE (r.contextid = $context->id OR r.contextid in $listofcontexts) + AND u.deleted = 0 $selectrole + AND (ul.courseid = $course->id OR ul.courseid IS NULL) + AND u.username <> 'guest' "; $where .= get_lastaccess_sql($accesssince); - - $wheresearch = ''; - if (!empty($search)) { - $LIKE = sql_ilike(); - $fullname = sql_fullname('u.firstname','u.lastname'); - $wheresearch .= ' AND ('. $fullname .' '. $LIKE .'\'%'. $search .'%\' OR email '. $LIKE .'\'%'. $search .'%\' OR idnumber '.$LIKE.' \'%'.$search.'%\') '; - - } - - if ($currentgroup) { // Displaying a group by choice - // FIX: TODO: This will not work if $currentgroup == 0, i.e. "those not in a group" - $from .= 'LEFT JOIN '.$CFG->prefix.'groups_members gm ON u.id = gm.userid '; - $where .= ' AND gm.groupid = '.$currentgroup; - } - - $totalcount = count_records_sql('SELECT COUNT(distinct u.id) '.$from.$where); // 1 person can have multiple assignments - - if ($table->get_sql_where()) { - $where .= ' AND '.$table->get_sql_where(); - } - - if ($table->get_sql_sort()) { - $sort = ' ORDER BY '.$table->get_sql_sort(); - } else { - $sort = ''; - } - - $matchcount = count_records_sql('SELECT COUNT(*) '.$from.$where.$wheresearch); - - $table->initialbars($totalcount > $perpage); - $table->pagesize($perpage, $matchcount); - - $students = get_records_sql($select.$from.$where.$wheresearch.$sort, - $table->get_page_start(), $table->get_page_size()); + $wheresearch = ''; + + if (!empty($search)) { + $LIKE = sql_ilike(); + $fullname = sql_fullname('u.firstname','u.lastname'); + $wheresearch .= ' AND ('. $fullname .' '. $LIKE .'\'%'. $search .'%\' OR email '. $LIKE .'\'%'. $search .'%\' OR idnumber '.$LIKE.' \'%'.$search.'%\') '; + + } + + if ($currentgroup) { // Displaying a group by choice + // FIX: TODO: This will not work if $currentgroup == 0, i.e. "those not in a group" + $from .= 'LEFT JOIN '.$CFG->prefix.'groups_members gm ON u.id = gm.userid '; + $where .= ' AND gm.groupid = '.$currentgroup; + } + + $totalcount = count_records_sql('SELECT COUNT(distinct u.id) '.$from.$where); // Each user could have > 1 role + + if ($table->get_sql_where()) { + $where .= ' AND '.$table->get_sql_where(); + } + + if ($table->get_sql_sort()) { + $sort = ' ORDER BY '.$table->get_sql_sort(); + } else { + $sort = ''; + } + + $matchcount = count_records_sql('SELECT COUNT(*) '.$from.$where.$wheresearch); + + $table->initialbars($totalcount > $perpage); + $table->pagesize($perpage, $matchcount); + + $students = get_records_sql($select.$from.$where.$wheresearch.$sort, + $table->get_page_start(), $table->get_page_size()); /// If there are multiple Roles in the course, then show a drop down menu for switching - - if ($rolenames) { - echo '
'; - echo get_string('currentrole', 'role').': '; - $rolenames = array(0 => get_string('all')) + $rolenames; - popup_form('index.php?contextid='.$contextid.'&roleid=', $rolenames, 'rolesform', $roleid, ''); - echo '
'; - } + if ($rolenames) { + echo '
'; + echo get_string('currentrole', 'role').': '; + $rolenames = array(0 => get_string('all')) + $rolenames; + popup_form('index.php?contextid='.$context->id.'&sifirst=&silast=&roleid=', $rolenames, + 'rolesform', $roleid, ''); + echo '
'; + } + if ($roleid) { if (!$currentrole = get_record('role','id',$roleid)) { error('That role does not exist'); } @@ -391,218 +387,193 @@ $heading .= ''; } print_heading($heading, 'center', 3); - - - if ($isteacher) { - echo ' - -'; - echo '
'; - echo ''; - echo ''; - } - - if ($CFG->longtimenosee > 0 && $CFG->longtimenosee < 1000 && $totalcount > 0) { - echo '

('.get_string('unusedaccounts', '', $CFG->longtimenosee).')

'; + + if ($bulkoperations) { + echo ' + + '; + echo ''; + echo ''; + echo ''; + } + + if ($CFG->longtimenosee > 0 && $CFG->longtimenosee < 1000 && $totalcount > 0) { + echo '

('.get_string('unusedaccounts', '', $CFG->longtimenosee).')

'; + } + + if ($fullmode) { // Print simple listing + if ($totalcount < 1) { + print_heading(get_string("nostudentsfound", "", $course->students)); + + } else { + if ($totalcount > $perpage) { + + $firstinitial = $table->get_initial_first(); + $lastinitial = $table->get_initial_last(); + $strall = get_string('all'); + $alpha = explode(',', get_string('alphabet')); + + // Bar of first initials + + echo '
'.get_string('firstname').' : '; + if(!empty($firstinitial)) { + echo ''.$strall.''; + } else { + echo ''.$strall.''; + } + foreach ($alpha as $letter) { + if ($letter == $firstinitial) { + echo ' '.$letter.''; } else { - echo ''.$strall.''; - } - foreach ($alpha as $letter) { - if ($letter == $lastinitial) { - echo ' '.$letter.''; - } else { - echo ' '.$letter.''; - } + echo ' '.$letter.''; } - echo '
'; - - print_paging_bar($matchcount, intval($table->get_page_start() / $perpage), $perpage, $baseurl.'&', 'spage'); - } - - if($matchcount > 0) { - foreach ($students as $student) { - print_user($student, $course, true); + echo ''; + + // Bar of last initials + + echo '
'.get_string('lastname').' : '; + if(!empty($lastinitial)) { + echo ''.$strall.''; + } else { + echo ''.$strall.''; + } + foreach ($alpha as $letter) { + if ($letter == $lastinitial) { + echo ' '.$letter.''; + } else { + echo ' '.$letter.''; } } - else { - print_heading(get_string('nothingtodisplay')); + echo '
'; + + print_paging_bar($matchcount, intval($table->get_page_start() / $perpage), $perpage, $baseurl.'&', 'spage'); + } + + if ($matchcount > 0) { + foreach ($students as $student) { + print_user($student, $course, true); } + + } else { + print_heading(get_string('nothingtodisplay')); } } - else { - $countrysort = (strpos($sort, 'country') !== false); - $timeformat = get_string('strftimedate'); - if (!empty($students)) { - foreach ($students as $student) { - if ($student->lastaccess) { - $lastaccess = format_time(time() - $student->lastaccess, $datestring); - } else { - $lastaccess = $strnever; - } - - if (empty($student->country)) { - $country = ''; + + } else { + $countrysort = (strpos($sort, 'country') !== false); + $timeformat = get_string('strftimedate'); + if (!empty($students)) { + foreach ($students as $student) { + if ($student->lastaccess) { + $lastaccess = format_time(time() - $student->lastaccess, $datestring); + } else { + $lastaccess = $strnever; + } + + if (empty($student->country)) { + $country = ''; + + } else { + if($countrysort) { + $country = '('.$student->country.') '.$countries[$student->country]; } else { - if($countrysort) { - $country = '('.$student->country.') '.$countries[$student->country]; - } - else { - $country = $countries[$student->country]; - } - } - - $data = array ( - print_user_picture($student->id, $course->id, $student->picture, false, true), - ''.fullname($student).''); - if (!isset($hiddenfields['city'])) { - $data[] = $student->city; - } - if (!isset($hiddenfields['country'])) { - $data[] = $country; - } - if (!isset($hiddenfields['lastaccess'])) { - $data[] = $lastaccess; + $country = $countries[$student->country]; } - if ($course->enrolperiod) { - if ($student->timeend) { - $data[] = userdate($student->timeend, $timeformat); - } else { - $data[] = get_string('unlimited'); - } - } - if ($isteacher) { - $data[] = ''; + } + + $data = array ( + print_user_picture($student->id, $course->id, $student->picture, false, true), + ''.fullname($student).''); + if (!isset($hiddenfields['city'])) { + $data[] = $student->city; + } + if (!isset($hiddenfields['country'])) { + $data[] = $country; + } + if (!isset($hiddenfields['lastaccess'])) { + $data[] = $lastaccess; + } + if ($course->enrolperiod) { + if ($student->timeend) { + $data[] = userdate($student->timeend, $timeformat); + } else { + $data[] = get_string('unlimited'); } - $table->add_data($data); - } - } - - $table->print_html(); - - } + if ($bulkoperations) { + $data[] = ''; + } + $table->add_data($data); - if ($isteacher) { - echo '
'; - echo ' '; - echo ' '; - $displaylist['messageselect.php'] = get_string('messageselectadd'); - if ($course->enrolperiod) { - $displaylist['extendenrol.php'] = get_string('extendenrol'); } - choose_from_menu ($displaylist, "formaction", "", get_string("withselectedusers"), "if(checksubmit(this.form))this.form.submit();", ""); - helpbutton("participantswithselectedusers", get_string("withselectedusers")); - echo ''; - } - - if ($isteacher && $totalcount > ($perpage*3)) { - echo '

'.get_string('search').': '."\n"; - echo ' 

'."\n"; - } - - if ($perpage == SHOW_ALL_PAGE_SIZE) { - echo ''; - } - else if ($matchcount > 0 && $perpage < $matchcount) { - echo ''; } - } else { -/// If no role is selected, then print an overview of the roles in this course - - $table->tablealign = 'center'; - $table->cellpadding = 5; - $table->cellspacing = 0; - $table->width = '20%'; - $table->head = array(get_string('roles', 'role'), get_string('users')); - $table->wrap = array('nowrap', 'nowrap'); - $table->align = array('right', 'center'); - - $baseurl = $CFG->wwwroot.'/user/index.php?contextid='.$context->id; - - foreach ($rolenames as $roleid => $rolename) { - $countusers = 0; - if ($contextusers = count_role_users($roleid, $context)) { - $countusers = count($contextusers); - } - if ($countusers) { - $table->data[] = array(''.$rolename.'', $countusers); - } else { - $table->data[] = array($rolename, $countusers); - } + $table->print_html(); + + } + + if ($bulkoperations) { + echo '
'; + echo ' '; + echo ' '; + $displaylist['messageselect.php'] = get_string('messageselectadd'); + if ($course->enrolperiod) { + $displaylist['extendenrol.php'] = get_string('extendenrol'); } + choose_from_menu ($displaylist, "formaction", "", get_string("withselectedusers"), "if(checksubmit(this.form))this.form.submit();", ""); + helpbutton("participantswithselectedusers", get_string("withselectedusers")); + echo ''; + echo ''; + echo '
'; + } - print_table($table); + if ($bulkoperations && $totalcount > ($perpage*3)) { + echo '

'.get_string('search').': '."\n"; + echo ' 

'."\n"; + } + if ($perpage == SHOW_ALL_PAGE_SIZE) { + echo ''; + + } else if ($matchcount > 0 && $perpage < $matchcount) { + echo ''; } - + print_footer($course); + + function get_lastaccess_sql($accesssince='') { if (empty($accesssince)) { return ''; diff --git a/version.php b/version.php index c71a1c7f73..16be5079f1 100644 --- a/version.php +++ b/version.php @@ -6,7 +6,7 @@ // This is compared against the values stored in the database to determine // whether upgrades should be performed (see lib/db/*.php) - $version = 2006092601; // YYYYMMDD = date + $version = 2006092800; // YYYYMMDD = date // XY = increments within a single day $release = '1.7 dev'; // Human-friendly version name