[opw-web] Add a withdrawn state for applications



commit 64d5d799c890d38c30f5ad8ac5e003dadf52a08b
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Tue Mar 18 16:04:41 2014 -0400

    Add a withdrawn state for applications
    
    Before the application deadline, allow applicants to delete their proposals.
    (They could do so before by resigning, but not otherwise.)
    
    After the application deadline, allow applicants to withdraw an application, which
    flags it as withdrawn, but does not delete it. Flag such applications in
    the view/manage projects screens.
    
    Make the resign function withdraw/delete as appropriate.

 lang/en-gb.php                                     |    9 ++-
 modules/mod_manage_projects.php                    |    2 +
 modules/mod_view_projects.php                      |  108 ++++++++++++++-----
 schema.sql                                         |    1 +
 .../html/tpl_manage_projects_item.html             |    2 +-
 skins/easterngreen/html/tpl_view_project.html      |   14 +++
 .../easterngreen/html/tpl_view_projects_item.html  |    2 +-
 utils.php                                          |   33 +++++-
 8 files changed, 134 insertions(+), 37 deletions(-)
---
diff --git a/lang/en-gb.php b/lang/en-gb.php
index 0363628..50674a5 100644
--- a/lang/en-gb.php
+++ b/lang/en-gb.php
@@ -183,6 +183,12 @@ $lang_data = array(
     'failed'                => 'Failed',
     'undecided'             => 'Undecided',
     'confirm_project_del'   => 'Deletion of a project is irreversible. Are you sure you want to continue?',
+    'withdrawn_notice'      => 'This application is withdrawn and will not receive consideration.',
+    'withdraw'              => 'Withdraw application',
+    'resubmit'              => 'Resubmit application',
+    'confirm_withdraw'      => 'Confirm application withdrawal',
+    'confirm_withdraw_exp'  => 'Are you sure you want to withdraw this application?',
+    'confirm_project_del'   => 'Deletion of a project is irreversible. Are you sure you want to continue?',
     'mentor_project'        => 'Willing to mentor',
     'mentor_remove'         => 'Remove myself as mentor',
     'view_project'          => 'View project details',
@@ -218,7 +224,8 @@ $lang_data = array(
                                '//mail.kde.org/mailman/listinfo/kde-soc-mentor" target="_blank">KDE SoC ' .
                                'Mentor Mailing List</a>, if you haven\'t done it already.',
     'confirm_resign'        => 'Confirm resignation',
-    'confirm_resign_exp'    => 'Are you sure you want to resign? Your submissions will get invalidated.',
+    'confirm_resign_exp_delete'   => 'Are you sure you want to resign? Your submissions will be deleted.',
+    'confirm_resign_exp_withdraw' => 'Are you sure you want to resign? Your submissions will be marked as 
withdrawn.',
     'confirm_resign_mentor_exp' => 'Are you sure you want to resign? You will be removed from any projects 
where you are currently listed as the mentor.',
     'cannot_resign'         => 'Cannot resign',
     'cannot_resign_mentor_exp' => 'Cannot resign as a mentor since you are currently mentoring accepted 
projects. Please contact an adminstrator to arrange for your projects to be transferred to another mentor.',
diff --git a/modules/mod_manage_projects.php b/modules/mod_manage_projects.php
index 501f860..4463024 100644
--- a/modules/mod_manage_projects.php
+++ b/modules/mod_manage_projects.php
@@ -141,6 +141,7 @@ $a = 1;
 foreach ($list_data as &$row)
 {
     $project_title = htmlspecialchars($row['title']);
+    $is_withdrawn = $row['is_withdrawn'] == 1;
     $username = $row['username'];
     $profile = $user->profile($username);
 
@@ -163,6 +164,7 @@ foreach ($list_data as &$row)
         'project_applicant'     => $profile,
         'ranking'               => $ranking,
         'ranking_name'          => 'ranking' . $project_id,
+        'withdrawn_visibility'  => $skin->visibility($is_withdrawn),
         'disabled'              => $can_edit ? '' : ' disabled',
         'opinion_select'        => build_opinion_select($row['org_opinion'], 'opinion' . $project_id, 
!$can_edit),
         'project_url'           => "?q=view_projects&amp;prg={$program_id}&amp;p={$project_id}",
diff --git a/modules/mod_view_projects.php b/modules/mod_view_projects.php
index 56d7a1e..27989b7 100644
--- a/modules/mod_view_projects.php
+++ b/modules/mod_view_projects.php
@@ -353,9 +353,7 @@ if ($action == 'editor')
 }
 else if ($action == 'delete')
 {
-    // Program ID should be supplied, and user must be an admin
-    $user->restrict($program_id > 0);
-    $user->restrict(false, true);
+    $user->restrict($project_permissions->can_delete);
 
     // Deletion was confirmed
     if ($confirm)
@@ -388,6 +386,54 @@ else if ($action == 'delete')
     $module_title = $lang->get('confirm_deletion');
     $module_data = $skin->output('tpl_confirm_box');
 }
+else if ($action == 'withdraw')
+{
+    $user->restrict($project_permissions->can_withdraw);
+
+    // Withdraw was confirmed
+    if ($confirm)
+    {
+        $user->check_csrf();
+
+        $sql = "UPDATE {$db->prefix}projects " .
+               "SET is_withdrawn = 1 " .
+               "WHERE id = ?";
+        $db->query($sql, $project_id);
+
+        // Purge the project cache
+        $cache->purge('projects');
+
+        // Redirect to project page
+        $core->redirect("?q=view_projects&prg={$program_id}&p={$project_id}");
+    }
+
+    // Assign confirm box data
+    $skin->assign(array(
+        'message_title'     => $lang->get('confirm_withdraw'),
+        'message_body'      => $lang->get('confirm_withdraw_exp'),
+        'cancel_url'        => "?q=view_projects&amp;prg={$program_id}&amp;p={$project_id}",
+    ));
+
+    // Output the module
+    $module_title = $lang->get('confirm_withdraw');
+    $module_data = $skin->output('tpl_confirm_box');
+}
+else if ($action == 'resubmit')
+{
+    $user->restrict($project_permissions->can_resubmit);
+    $user->check_csrf();
+
+    $sql = "UPDATE {$db->prefix}projects " .
+           "SET is_withdrawn = 0 " .
+           "WHERE id = ?";
+    $db->query($sql, $project_id);
+
+    // Purge the project cache
+    $cache->purge('projects');
+
+    // Redirect to project page
+    $core->redirect("?q=view_projects&prg={$program_id}&p={$project_id}");
+}
 else if ($action == 'view')
 {
     // Program and Project IDs are mandatory here
@@ -581,11 +627,14 @@ else if ($action == 'view')
         'attachments_list'          => $attachments_list,
         'success_message'           => isset($success_message) ? $success_message : '',
         'success_visibility'        => $skin->visibility(empty($success_message), true),
+        'is_withdrawn_visibility'   => $skin->visibility($project_data['is_withdrawn'] == 1),
         'mentor_visibility'         => $skin->visibility($can_view_mentor),
         'edit_visibility'           => $skin->visibility($project_permissions->can_edit),
         'attach_visibility'         => $skin->visibility($is_owner && $project_permissions->can_edit),
         'attachments_visibility'    => $skin->visibility(count($attachment_data) > 0),
-        'delete_visibility'         => $skin->visibility($user->is_admin),
+        'delete_visibility'         => $skin->visibility($project_permissions->can_delete),
+        'withdraw_visibility'       => $skin->visibility($project_permissions->can_withdraw),
+        'resubmit_visibility'       => $skin->visibility($project_permissions->can_resubmit),
         'mentor_project_visibility' => $skin->visibility($can_mentor),
         'mentor_remove_visibility'  => $skin->visibility($can_remove_mentor),
         'actions_visibility'        => $skin->visibility(($is_owner && $project_permissions->can_edit) ||
@@ -734,6 +783,7 @@ else if ($action == 'user' || $action == 'proposed' || $action == 'accepted' ||
                 'project_title'         => $project_title,
                 'project_description'   => nl2br($project_desc),
                 'project_organization'  => htmlspecialchars($row['organization_title']),
+                'withdrawn_visibility'  => $skin->visibility($row['is_withdrawn'] == 1),
                 'project_url'           => "?q=view_projects&amp;prg={$program_id}&amp;p={$row['id']}",
                 'approve_url'           => "?q=view_projects&amp;a=approve&amp;prg={$program_id}" .
                                            "&amp;p={$row['id']}&amp;r={$return_url}",
@@ -866,7 +916,7 @@ else if ($action == 'apply')
     $module_title = $lang->get('apply_mentor');
     $module_data = $skin->output('tpl_apply_mentor');
 }
-else if ($action == 'resign' || ($role == 'm' || $role == 'i'))
+else if ($action == 'resign' && ($role == 'm' || $role == 'i'))
 {
     // See if mentoring any accepted projected projects
 
@@ -933,6 +983,8 @@ else if ($action == 'resign')
     // We need program ID for this action
     $user->restrict($program_id > 0);
 
+    $delete_projects = $core->timestamp < $program_data['dl_student'];
+
     $params = array('program_id' => $program_id,
                     'username' => $user->username,
                     'timestamp' => $core->timestamp);
@@ -941,15 +993,8 @@ else if ($action == 'resign')
     {
         $user->check_csrf();
 
-        // Check if program has already started
-        $sql = "SELECT COUNT(*) AS count " .
-               "FROM {$db->prefix}programs " .
-               "WHERE id = :program_id " .
-               "AND start_time <= :timestamp";
-        $prog_count = $db->query($sql, $params, true);
-
         // If program already started, mark student as failed
-        if ($prog_count['count'] > 0)
+        if ($core->timestamp >= $program_data['start_time'])
         {
             $sql = "UPDATE {$db->prefix}participants " .
                    "SET passed = 0 " .
@@ -958,26 +1003,24 @@ else if ($action == 'resign')
             $db->query($sql, $params);
         }
 
-        // Else, simply delete the proposals
-        else
+        $sql = "SELECT * FROM {$db->prefix}participants " .
+               "WHERE program_id = :program_id " .
+               "AND username = :username";
+        $project_data = $db->query($sql, $params);
+
+        // Student has one or more proposals
+        if ($project_data)
         {
-            $sql = "SELECT * FROM {$db->prefix}participants " .
-                   "WHERE program_id = :program_id " .
-                   "AND username = :username";
-            $project_data = $db->query($sql, $params);
+            $projects_ary = array();
 
-            // Student has one or more proposals
-            if ($project_data)
+            foreach ($project_data as $row)
             {
-                $projects_ary = array();
-
-                foreach ($project_data as $row)
-                {
-                    $projects_ary[] = $row['project_id'];
-                }
+                $projects_ary[] = $row['project_id'];
+            }
 
-                $projects = implode(',', $projects_ary);
+            $projects = implode(',', $projects_ary);
 
+            if ($delete_projects) {
                 // Delete all the projects
                 $sql = "DELETE FROM {$db->prefix}participants " .
                        "WHERE project_id IN ({$projects})";
@@ -986,6 +1029,11 @@ else if ($action == 'resign')
                 $sql = "DELETE FROM {$db->prefix}projects " .
                        "WHERE id IN ({$projects})";
                 $db->query($sql);
+            } else {
+                $sql = "UPDATE {$db->prefix}projects " .
+                       "SET is_withdrawn = 1 " .
+                       "WHERE project_id IN ({$projects})";
+                $db->query($sql);
             }
         }
 
@@ -1006,7 +1054,9 @@ else if ($action == 'resign')
     // Assign confirm box data
     $skin->assign(array(
         'message_title'     => $lang->get('confirm_resign'),
-        'message_body'      => $lang->get('confirm_resign_exp'),
+        'message_body'      => $delete_applications ?
+                                    $lang->get('confirm_resign_exp_delete') :
+                                    $lang->get('confirm_resign_exp_withdraw'),
         'cancel_url'        => "?q=program_home&prg={$program_id}",
     ));
 
diff --git a/schema.sql b/schema.sql
index 4e01028..51eb800 100644
--- a/schema.sql
+++ b/schema.sql
@@ -35,6 +35,7 @@ CREATE TABLE `opw_projects` (
   `organization_id` mediumint(6) unsigned,
   `is_accepted` tinyint(1) NOT NULL DEFAULT -1,
   `is_complete` tinyint(1) NOT NULL DEFAULT 0,
+  `is_withdrawn` tinyint(1) NOT NULL DEFAULT 0,
   `ranking` float NOT NULL DEFAULT -1,
   /* 'n' - No contribution
    * 'y' - No contribution, will not accept
diff --git a/skins/easterngreen/html/tpl_manage_projects_item.html 
b/skins/easterngreen/html/tpl_manage_projects_item.html
index 97dba34..abb76ba 100644
--- a/skins/easterngreen/html/tpl_manage_projects_item.html
+++ b/skins/easterngreen/html/tpl_manage_projects_item.html
@@ -2,7 +2,7 @@
     <td>
         <a href="[[project_url]]">
             [[project_title]]
-        </a>
+        </a><span class="[[withdrawn_visibility]]">&nbsp;<span class="badge">Withdrawn</span></span>
     </td>
 
     <td>
diff --git a/skins/easterngreen/html/tpl_view_project.html b/skins/easterngreen/html/tpl_view_project.html
index d49d615..253755d 100644
--- a/skins/easterngreen/html/tpl_view_project.html
+++ b/skins/easterngreen/html/tpl_view_project.html
@@ -16,6 +16,10 @@
     {{subscribe_mentor}}
 </div>
 
+<div class="alert alert-error [[is_withdrawn_visibility]]">
+    {{withdrawn_notice}}
+</div>
+
 <div class="project-data">
     <div class="row">
         <div class="span2">{{project_title}}</div>
@@ -86,6 +90,16 @@
             {{delete}}
         </a>
 
+        <a href="?q=view_projects&amp;a=withdraw&amp;prg=[[program_id]]&amp;p=[[project_id]]"
+           class="btn btn-danger [[withdraw_visibility]]">
+            {{withdraw}}
+        </a>
+
+        <a href="#" onclick="submitForm(event, 
'?q=view_projects&amp;a=resubmit&amp;prg=[[program_id]]&amp;p=[[project_id]]')"
+           class="btn [[resubmit_visibility]]">
+            {{resubmit}}
+        </a>
+
         <a href="?q=attachment&amp;a=add&amp;prg=[[program_id]]&amp;p=[[project_id]]"
            class="btn [[attach_visibility]]">
             {{add_attachment}}
diff --git a/skins/easterngreen/html/tpl_view_projects_item.html 
b/skins/easterngreen/html/tpl_view_projects_item.html
index 65f1167..525cd86 100644
--- a/skins/easterngreen/html/tpl_view_projects_item.html
+++ b/skins/easterngreen/html/tpl_view_projects_item.html
@@ -10,7 +10,7 @@
     </td>
 
     <td>
-        [[project_description]]
+        <span class="[[withdrawn_visibility]]"><span 
class="badge">Withdrawn</span>&nbsp;</span>[[project_description]]
     </td>
 
     <td>
diff --git a/utils.php b/utils.php
index a777a76..05b3e0a 100644
--- a/utils.php
+++ b/utils.php
@@ -82,6 +82,9 @@ class ProjectPermissions {
         $is_owner = false;
         $can_view = false;
         $can_edit = false;
+        $can_withdraw = false;
+        $can_resubmit = false;
+        $can_delete = false;
         $can_change_organization = false;
 
         if ($role == 's') {
@@ -124,29 +127,46 @@ class ProjectPermissions {
             if ($user->is_admin) {
                 $can_edit = true;
                 $can_change_organization = true;
+                $can_withdraw = $project_data['is_withdrawn'] == 0;
+                $can_resubmit = $project_data['is_withdrawn'] == 1;
+                $can_delete = true;
             } else if ($is_owner && $role == 's') {
-                $can_edit = true;
-                $can_change_organization = true;
-
-                // Do not let anyone but admins edit rejected projects`
                 if ($project_data['is_accepted'] == 0) {
+                    // Do not let anyone but admins edit rejected projects`
                     $can_edit = false;
                     $can_change_organization = false;
+                    $can_withdraw = false;
+                    $can_resubmit = false;
+                    $can_delete = false;
                 } else if ($core->timestamp >= $program_data['dl_mentor']) {
                     // Past the selection deadline, students cannot edit anything
                     $can_edit = false;
                     $can_change_organization = false;
+                    $can_withdraw = $project_data['is_withdrawn'] == 0;
+                    $can_resubmit = false;
+                    $can_delete = false;
                 } else if ($core->timestamp > $program_data['dl_student']) {
+                    $can_edit = true;
+
                     // Projects submitted to organizations that are no longer taking
                     // new submissions can't be moved by the student to a different
                     // organization, because they can't be moved back.
-
                     if (!$can_submit) {
                         $can_change_organization = false;
                     } else if ($late_submission) {
                         $organization_data = $cache->get_organization_data($project_data['organization_id']);
                         $can_change_organization = $organization_data['late_submission'] != 0;
                     }
+
+                    $can_withdraw = $project_data['is_withdrawn'] == 0;
+                    $can_resubmit = $project_data['is_withdrawn'] == 1;
+                    $can_delete = false;
+                } else {
+                    $can_edit = true;
+                    $can_change_organization = true;
+                    $can_withdraw = false;
+                    $can_resubmit = false;
+                    $can_delete = true;
                 }
             }
         }
@@ -156,6 +176,9 @@ class ProjectPermissions {
         $this->is_owner = $is_owner;
         $this->can_view = $can_view;
         $this->can_edit = $can_edit;
+        $this->can_withdraw = $can_withdraw;
+        $this->can_resubmit = $can_resubmit;
+        $this->can_delete = $can_delete;
         $this->can_change_organization = $can_change_organization;
     }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]