diff --git a/src/IDF/Form/Admin/ProjectDelete.php b/src/IDF/Form/Admin/ProjectDelete.php new file mode 100644 index 0000000..67ee0e5 --- /dev/null +++ b/src/IDF/Form/Admin/ProjectDelete.php @@ -0,0 +1,88 @@ +project = $extra['project']; + $this->user = $extra['user']; + $this->fields['code'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Confirmation code'), + 'initial' => '', + )); + $this->fields['agree'] = new Pluf_Form_Field_Boolean( + array('required' => true, + 'label' => __('I have made a backup of all the important data of this project.'), + 'initial' => '', + )); + } + + public function clean_code() + { + $code = $this->cleaned_data['code']; + if ($code != $this->getCode()) { + throw new Pluf_Form_Invalid(__('The confirmation code does not match. Please provide a valid confirmation code to delete the project.')); + } + return $code; + } + + public function clean_agree() + { + if (!$this->cleaned_data['agree']) { + throw new Pluf_Form_Invalid(__('Sorry, you really need to backup your data before deletion.')); + } + return $this->cleaned_data['agree']; + } + + public function getCode() + { + return substr(md5(Pluf::f('secret_key').$this->user->id.'.'.$this->project->id), + 0, 8); + } + + + public function save($commit=true) + { + if (!$this->isValid()) { + throw new Exception(__('Cannot save the model from an invalid form.')); + } + // So, we drop the project, it will cascade and delete all the + // elements of the project. For large projects, this may use + // quite some memory. + $this->project->delete(); + return true; + } +} + + diff --git a/src/IDF/Project.php b/src/IDF/Project.php index 31bae65..06960d4 100644 --- a/src/IDF/Project.php +++ b/src/IDF/Project.php @@ -425,6 +425,57 @@ class IDF_Project extends Pluf_Model return $this->_pconf; } + /** + * Get simple statistics about the project. + * + * This returns an associative array with number of tickets, + * number of downloads, etc. + * + * @return array Stats + */ + public function getStats() + { + $stats = array(); + $stats['total'] = 0; + $what = array('downloads' => 'IDF_Upload', + 'reviews' => 'IDF_Review', + 'issues' => 'IDF_Issue', + 'docpages' => 'IDF_WikiPage', + 'commits' => 'IDF_Commit', + ); + foreach ($what as $key=>$m) { + $i = Pluf::factory($m)->getCount(array('filter' => 'project='.(int)$this->id)); + $stats[$key] = $i; + $stats['total'] += $i; + } + /** + * [signal] + * + * IDF_Project::getStats + * + * [sender] + * + * IDF_Project + * + * [description] + * + * This signal allows an application to update the statistics + * array of a project. For example to add the on disk size + * of the repository if available. + * + * [parameters] + * + * array('project' => $project, + * 'stats' => $stats) + * + */ + $params = array('project' => $this, + 'stats' => $stats); + Pluf_Signal::send('IDF_Project::getStats', + 'IDF_Project', $params); + return $stats; + } + /** * Needs to be called when you update the memberships of a * project. diff --git a/src/IDF/Views/Admin.php b/src/IDF/Views/Admin.php index d9693c0..8eed08e 100644 --- a/src/IDF/Views/Admin.php +++ b/src/IDF/Views/Admin.php @@ -142,6 +142,39 @@ class IDF_Views_Admin $request); } + /** + * Deletion of a project. + * + * Only the forge administrator can perform this operation. + */ + public $projectDelete_precond = array('Pluf_Precondition::adminRequired'); + public function projectDelete($request, $match) + { + $project = Pluf_Shortcuts_GetObjectOr404('IDF_Project', $match[1]); + $title = sprintf(__('Delete %s Project'), $project); + $extra = array('project' => $project, + 'user' => $request->user); + if ($request->method == 'POST') { + $form = new IDF_Form_Admin_ProjectDelete($request->POST, $extra); + if ($form->isValid()) { + $project = $form->save(); + $request->user->setMessage(__('The project has been deleted.')); + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Admin::projects'); + return new Pluf_HTTP_Response_Redirect($url); + } + } else { + $form = new IDF_Form_Admin_ProjectDelete(null, $extra); + } + return Pluf_Shortcuts_RenderToResponse('idf/gadmin/projects/delete.html', + array( + 'page_title' => $title, + 'form' => $form, + 'stats' => $project->getStats(), + 'code' => $form->getCode(), + ), + $request); + } + /** * Users overview. * diff --git a/src/IDF/conf/urls.php b/src/IDF/conf/urls.php index 57805cb..b75c869 100644 --- a/src/IDF/conf/urls.php +++ b/src/IDF/conf/urls.php @@ -417,6 +417,12 @@ $ctl[] = array('regex' => '#^/admin/projects/create/$#', 'model' => 'IDF_Views_Admin', 'method' => 'projectCreate'); +$ctl[] = array('regex' => '#^/admin/projects/(\d+)/delete/$#', + 'base' => $base, + 'priority' => 4, + 'model' => 'IDF_Views_Admin', + 'method' => 'projectDelete'); + $ctl[] = array('regex' => '#^/admin/users/$#', 'base' => $base, 'priority' => 4, diff --git a/src/IDF/templates/idf/gadmin/projects/delete.html b/src/IDF/templates/idf/gadmin/projects/delete.html new file mode 100644 index 0000000..bbf14ae --- /dev/null +++ b/src/IDF/templates/idf/gadmin/projects/delete.html @@ -0,0 +1,72 @@ +{extends "idf/gadmin/projects/base.html"} +{block body} +{if $form.errors} +
+{/if} + +{trans 'Tab'} | {trans 'Number'} |
---|---|
{trans 'Downloads'} | {$stats['downloads']} |
{trans 'Code reviews'} | {$stats['reviews']} |
{trans 'Commits'} | {$stats['commits']} |
{trans 'Issues'} | {$stats['issues']} |
{trans 'Documentation pages'} | {$stats['docpages']} |
{blocktrans} +Attention! Deleting a project is a one second operation +with the consequences that all the data related to the +project will be deleted. +{/blocktrans}
+