diff --git a/src/IDF/Form/UpdateUpload.php b/src/IDF/Form/UpdateUpload.php
new file mode 100644
index 0000000..6620faf
--- /dev/null
+++ b/src/IDF/Form/UpdateUpload.php
@@ -0,0 +1,140 @@
+user = $extra['user'];
+ $this->project = $extra['project'];
+ $this->upload = $extra['upload'];
+
+ $this->fields['summary'] = new Pluf_Form_Field_Varchar(
+ array('required' => true,
+ 'label' => __('Summary'),
+ 'initial' => $this->upload->summary,
+ 'widget_attrs' => array(
+ 'maxlength' => 200,
+ 'size' => 67,
+ ),
+ ));
+ $tags = $this->upload->get_tags_list();
+ for ($i=1;$i<4;$i++) {
+ $initial = '';
+ if (isset($tags[$i-1])) {
+ if ($tags[$i-1]->class != 'Other') {
+ $initial = (string) $tags[$i-1];
+ } else {
+ $initial = $tags[$i-1]->name;
+ }
+ }
+ $this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
+ array('required' => false,
+ 'label' => __('Labels'),
+ 'initial' => $initial,
+ 'widget_attrs' => array(
+ 'maxlength' => 50,
+ 'size' => 20,
+ ),
+ ));
+ }
+ }
+
+ /**
+ * Validate the interconnection in the form.
+ */
+ public function clean()
+ {
+ $conf = new IDF_Conf();
+ $conf->setProject($this->project);
+ $onemax = array();
+ foreach (split(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
+ if (trim($class) != '') {
+ $onemax[] = mb_strtolower(trim($class));
+ }
+ }
+ $count = array();
+ for ($i=1;$i<4;$i++) {
+ $this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
+ if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
+ list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
+ list($class, $name) = array(mb_strtolower(trim($class)),
+ trim($name));
+ } else {
+ $class = 'other';
+ $name = $this->cleaned_data['label'.$i];
+ }
+ if (!isset($count[$class])) $count[$class] = 1;
+ else $count[$class] += 1;
+ if (in_array($class, $onemax) and $count[$class] > 1) {
+ if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
+ $this->errors['label'.$i][] = sprintf(__('You cannot provide more than label from the %s class to an issue.'), $class);
+ throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
+ }
+ }
+ return $this->cleaned_data;
+ }
+
+ /**
+ * Save the model in the database.
+ *
+ * @param bool Commit in the database or not. If not, the object
+ * is returned but not saved in the database.
+ * @return Object Model with data set from the form.
+ */
+ function save($commit=true)
+ {
+ if (!$this->isValid()) {
+ throw new Exception(__('Cannot save the model from an invalid form.'));
+ }
+ // Add a tag for each label
+ $tags = array();
+ for ($i=1;$i<4;$i++) {
+ if (strlen($this->cleaned_data['label'.$i]) > 0) {
+ if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
+ list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
+ list($class, $name) = array(trim($class), trim($name));
+ } else {
+ $class = 'Other';
+ $name = trim($this->cleaned_data['label'.$i]);
+ }
+ $tag = IDF_Tag::add($name, $this->project, $class);
+ $tags[] = $tag->id;
+ }
+ }
+ // Create the upload
+ $this->upload->summary = trim($this->cleaned_data['summary']);
+ $this->upload->update();
+ $this->upload->batchAssoc('IDF_Tag', $tags);
+ return $this->upload;
+ }
+}
+
diff --git a/src/IDF/Form/Upload.php b/src/IDF/Form/Upload.php
new file mode 100644
index 0000000..c547ae2
--- /dev/null
+++ b/src/IDF/Form/Upload.php
@@ -0,0 +1,152 @@
+user = $extra['user'];
+ $this->project = $extra['project'];
+
+ $this->fields['summary'] = new Pluf_Form_Field_Varchar(
+ array('required' => true,
+ 'label' => __('Summary'),
+ 'initial' => '',
+ 'widget_attrs' => array(
+ 'maxlength' => 200,
+ 'size' => 67,
+ ),
+ ));
+ $this->fields['file'] = new Pluf_Form_Field_File(
+ array('required' => true,
+ 'label' => __('File'),
+ 'initial' => '',
+ 'move_function_params' => array('upload_path' => Pluf::f('upload_path').'/'.$this->project->shortname.'/files',
+ 'upload_path_create' => true),
+
+ ));
+ for ($i=1;$i<4;$i++) {
+ $this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
+ array('required' => false,
+ 'label' => __('Labels'),
+ 'widget_attrs' => array(
+ 'maxlength' => 50,
+ 'size' => 20,
+ ),
+ ));
+ }
+ }
+
+
+ public function clean_file()
+ {
+ if (!preg_match('/\.(png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|wmv|zip)$/i', $this->cleaned_data['file'])) {
+ throw new Pluf_Form_Invalid(__('For security reason, you cannot upload a file with this extension.'));
+ }
+ return $this->cleaned_data['file'];
+ }
+
+ /**
+ * Validate the interconnection in the form.
+ */
+ public function clean()
+ {
+ $conf = new IDF_Conf();
+ $conf->setProject($this->project);
+ $onemax = array();
+ foreach (split(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
+ if (trim($class) != '') {
+ $onemax[] = mb_strtolower(trim($class));
+ }
+ }
+ $count = array();
+ for ($i=1;$i<4;$i++) {
+ $this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
+ if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
+ list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
+ list($class, $name) = array(mb_strtolower(trim($class)),
+ trim($name));
+ } else {
+ $class = 'other';
+ $name = $this->cleaned_data['label'.$i];
+ }
+ if (!isset($count[$class])) $count[$class] = 1;
+ else $count[$class] += 1;
+ if (in_array($class, $onemax) and $count[$class] > 1) {
+ if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
+ $this->errors['label'.$i][] = sprintf(__('You cannot provide more than label from the %s class to an issue.'), $class);
+ throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
+ }
+ }
+ return $this->cleaned_data;
+ }
+
+ /**
+ * Save the model in the database.
+ *
+ * @param bool Commit in the database or not. If not, the object
+ * is returned but not saved in the database.
+ * @return Object Model with data set from the form.
+ */
+ function save($commit=true)
+ {
+ if (!$this->isValid()) {
+ throw new Exception(__('Cannot save the model from an invalid form.'));
+ }
+ // Add a tag for each label
+ $tags = array();
+ for ($i=1;$i<4;$i++) {
+ if (strlen($this->cleaned_data['label'.$i]) > 0) {
+ if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
+ list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
+ list($class, $name) = array(trim($class), trim($name));
+ } else {
+ $class = 'Other';
+ $name = trim($this->cleaned_data['label'.$i]);
+ }
+ $tags[] = IDF_Tag::add($name, $this->project, $class);
+ }
+ }
+ // Create the upload
+ $upload = new IDF_Upload();
+ $upload->project = $this->project;
+ $upload->submitter = $this->user;
+ $upload->summary = trim($this->cleaned_data['summary']);
+ $upload->file = $this->cleaned_data['file'];
+ $upload->filesize = filesize(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']);
+ $upload->downloads = 0;
+ $upload->create();
+ foreach ($tags as $tag) {
+ $upload->setAssoc($tag);
+ }
+ return $upload;
+ }
+}
+
diff --git a/src/IDF/Form/UploadConf.php b/src/IDF/Form/UploadConf.php
new file mode 100644
index 0000000..bee8701
--- /dev/null
+++ b/src/IDF/Form/UploadConf.php
@@ -0,0 +1,70 @@
+fields['labels_download_predefined'] = new Pluf_Form_Field_Varchar(
+ array('required' => true,
+ 'label' => __('Predefined download labels'),
+ 'initial' => self::init_predefined,
+ 'widget_attrs' => array('rows' => 13,
+ 'cols' => 75),
+ 'widget' => 'Pluf_Form_Widget_TextareaInput',
+ ));
+
+ $this->fields['labels_download_one_max'] = new Pluf_Form_Field_Varchar(
+ array('required' => false,
+ 'label' => __('Each download may have at most one label with each of these classes'),
+ 'initial' => self::init_one_max,
+ 'widget_attrs' => array('size' => 60),
+ ));
+
+ }
+}
+
+
diff --git a/src/IDF/Migrations/1Download.php b/src/IDF/Migrations/1Download.php
new file mode 100644
index 0000000..dcda585
--- /dev/null
+++ b/src/IDF/Migrations/1Download.php
@@ -0,0 +1,52 @@
+model = new $model();
+ $schema->createTables();
+ }
+}
+
+function IDF_Migrations_1Download_down($params=null)
+{
+ $models = array(
+ 'IDF_Upload',
+ );
+ $db = Pluf::db();
+ $schema = new Pluf_DB_Schema($db);
+ foreach ($models as $model) {
+ $schema->model = new $model();
+ $schema->dropTables();
+ }
+}
\ No newline at end of file
diff --git a/src/IDF/Migrations/Install.php b/src/IDF/Migrations/Install.php
index 4cc6d26..d255ed8 100644
--- a/src/IDF/Migrations/Install.php
+++ b/src/IDF/Migrations/Install.php
@@ -35,6 +35,7 @@ function IDF_Migrations_Install_setup($params=null)
'IDF_Issue',
'IDF_IssueComment',
'IDF_Conf',
+ 'IDF_Upload',
);
$db = Pluf::db();
$schema = new Pluf_DB_Schema($db);
@@ -64,6 +65,7 @@ function IDF_Migrations_Install_teardown($params=null)
$perm = Pluf_Permission::getFromString('IDF.project-owner');
if ($perm) $perm->delete();
$models = array(
+ 'IDF_Upload',
'IDF_Conf',
'IDF_IssueComment',
'IDF_Issue',
diff --git a/src/IDF/Precondition.php b/src/IDF/Precondition.php
index 9fc1f76..fb07330 100644
--- a/src/IDF/Precondition.php
+++ b/src/IDF/Precondition.php
@@ -40,4 +40,25 @@ class IDF_Precondition
}
return new Pluf_HTTP_Response_Forbidden($request);
}
+
+ /**
+ * Check if the user is project owner or member.
+ *
+ * @param Pluf_HTTP_Request
+ * @return mixed
+ */
+ static public function projectMemberOrOwner($request)
+ {
+ $res = Pluf_Precondition::loginRequired($request);
+ if (true !== $res) {
+ return $res;
+ }
+ if ($request->user->hasPerm('IDF.project-owner', $request->project)
+ or
+ $request->user->hasPerm('IDF.project-member', $request->project)
+ ) {
+ return true;
+ }
+ return new Pluf_HTTP_Response_Forbidden($request);
+ }
}
\ No newline at end of file
diff --git a/src/IDF/Upload.php b/src/IDF/Upload.php
new file mode 100644
index 0000000..2031fdd
--- /dev/null
+++ b/src/IDF/Upload.php
@@ -0,0 +1,143 @@
+_a['table'] = 'idf_uploads';
+ $this->_a['model'] = __CLASS__;
+ $this->_a['cols'] = array(
+ // It is mandatory to have an "id" column.
+ 'id' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Sequence',
+ 'blank' => true,
+ ),
+ 'project' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Foreignkey',
+ 'model' => 'IDF_Project',
+ 'blank' => false,
+ 'verbose' => __('project'),
+ 'relate_name' => 'issues',
+ ),
+ 'summary' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Varchar',
+ 'blank' => false,
+ 'size' => 250,
+ 'verbose' => __('summary'),
+ ),
+ 'file' =>
+ array(
+ 'type' => 'Pluf_DB_Field_File',
+ 'blank' => false,
+ 'default' => 0,
+ 'verbose' => __('file'),
+ 'help_text' => __('The path is relative to the upload path.'),
+ ),
+ 'filesize' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Integer',
+ 'blank' => false,
+ 'default' => 0,
+ 'verbose' => __('file size in bytes'),
+ ),
+ 'submitter' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Foreignkey',
+ 'model' => 'Pluf_User',
+ 'blank' => false,
+ 'verbose' => __('submitter'),
+ 'relate_name' => 'submitted_issue',
+ ),
+ 'tags' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Manytomany',
+ 'blank' => true,
+ 'model' => 'IDF_Tag',
+ 'verbose' => __('labels'),
+ ),
+ 'downloads' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Integer',
+ 'blank' => false,
+ 'default' => 0,
+ 'verbose' => __('number of downloads'),
+ ),
+ 'creation_dtime' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Datetime',
+ 'blank' => true,
+ 'verbose' => __('creation date'),
+ ),
+ 'modif_dtime' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Datetime',
+ 'blank' => true,
+ 'verbose' => __('modification date'),
+ ),
+ );
+ $this->_a['idx'] = array(
+ 'modif_dtime_idx' =>
+ array(
+ 'col' => 'modif_dtime',
+ 'type' => 'normal',
+ ),
+ );
+ $table = $this->_con->pfx.'idf_tag_idf_upload_assoc';
+ $this->_a['views'] = array(
+ 'join_tags' =>
+ array(
+ 'join' => 'LEFT JOIN '.$table
+ .' ON idf_upload_id=id',
+ ),
+ );
+ }
+
+ function __toString()
+ {
+ return $this->file;
+ }
+
+ function _toIndex()
+ {
+ return '';
+ }
+
+ function preSave()
+ {
+ if ($this->id == '') {
+ $this->creation_dtime = gmdate('Y-m-d H:i:s');
+ }
+ $this->modif_dtime = gmdate('Y-m-d H:i:s');
+ }
+}
\ No newline at end of file
diff --git a/src/IDF/Views/Download.php b/src/IDF/Views/Download.php
new file mode 100644
index 0000000..acd3ecc
--- /dev/null
+++ b/src/IDF/Views/Download.php
@@ -0,0 +1,200 @@
+project;
+ $title = sprintf(__('%s Downloads'), (string) $prj);
+ // Paginator to paginate the files to download.
+ $pag = new Pluf_Paginator(new IDF_Upload());
+ $pag->class = 'recent-issues';
+ $pag->item_extra_props = array('project_m' => $prj,
+ 'shortname' => $prj->shortname);
+ $pag->summary = __('This table shows the files to download.');
+ $pag->action = array('IDF_Views_Download::index', array($prj->shortname));
+ $pag->edit_action = array('IDF_Views_Download::view', 'shortname', 'id');
+ $list_display = array(
+ 'file' => __('File'),
+ array('summary', 'IDF_Views_Download_SummaryAndLabels', __('Summary')),
+ array('filesize', 'IDF_Views_Download_Size', __('Size')),
+ array('modif_dtime', 'Pluf_Paginator_DateYMD', __('Uploaded')),
+ );
+ $pag->configure($list_display, array(), array('file', 'filesize', 'modif_dtime'));
+ $pag->items_per_page = 10;
+ $pag->no_results_text = __('No downloads were found.');
+ $pag->sort_order = array('file', 'ASC');
+ $pag->setFromRequest($request);
+ return Pluf_Shortcuts_RenderToResponse('downloads/index.html',
+ array('project' => $prj,
+ 'page_title' => $title,
+ 'downloads' => $pag,
+ ),
+ $request);
+
+ }
+
+ /**
+ * View details of a file.
+ */
+ public function view($request, $match)
+ {
+ $prj = $request->project;
+ $upload = Pluf_Shortcuts_GetObjectOr404('IDF_Upload', $match[2]);
+ $title = sprintf(__('Download %s'), $upload->summary);
+ $form = false;
+ if ($request->method == 'POST' and
+ true === IDF_Precondition::projectMemberOrOwner($request)) {
+
+ $form = new IDF_Form_UpdateUpload($request->POST,
+ array('project' => $prj,
+ 'upload' => $upload,
+ 'user' => $request->user));
+ if ($form->isValid()) {
+ $upload = $form->save();
+ $urlfile = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
+ array($prj->shortname, $upload->id));
+ $request->user->setMessage(sprintf(__('The file %2$s has been updated.'), $urlfile, Pluf_esc($upload->file)));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::index',
+ array($prj->shortname));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+ } elseif (true === IDF_Precondition::projectMemberOrOwner($request)) {
+ $form = new IDF_Form_UpdateUpload(null,
+ array('upload' => $upload,
+ 'project' => $prj,
+ 'user' => $request->user));
+ }
+ return Pluf_Shortcuts_RenderToResponse('downloads/view.html',
+ array(
+ 'file' => $upload,
+ 'auto_labels' => self::autoCompleteArrays($prj),
+ 'page_title' => $title,
+ 'form' => $form,
+ ),
+ $request);
+ }
+
+ /**
+ * Submit a new file for download.
+ */
+ public $submit_precond = array('IDF_Precondition::projectMemberOrOwner');
+ public function submit($request, $match)
+ {
+ $prj = $request->project;
+ $title = __('New Download');
+ if ($request->method == 'POST') {
+ $form = new IDF_Form_Upload(array_merge($request->POST, $request->FILES),
+ array('project' => $prj,
+ 'user' => $request->user));
+ if ($form->isValid()) {
+ $upload = $form->save();
+ $urlfile = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
+ array($prj->shortname, $upload->id));
+ $request->user->setMessage(sprintf(__('The file has been uploaded.'), $urlfile));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::index',
+ array($prj->shortname));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+ } else {
+ $form = new IDF_Form_Upload(null,
+ array('project' => $prj,
+ 'user' => $request->user));
+ }
+ return Pluf_Shortcuts_RenderToResponse('downloads/submit.html',
+ array(
+ 'auto_labels' => self::autoCompleteArrays($prj),
+ 'page_title' => $title,
+ 'form' => $form,
+ ),
+ $request);
+ }
+
+ /**
+ * Create the autocomplete arrays for the little AJAX stuff.
+ */
+ public static function autoCompleteArrays($project)
+ {
+ $conf = new IDF_Conf();
+ $conf->setProject($project);
+ $st = preg_split("/\015\012|\015|\012/",
+ $conf->getVal('labels_downloads_predefined', IDF_Form_UploadConf::init_predefined), -1, PREG_SPLIT_NO_EMPTY);
+ $auto = '';
+ foreach ($st as $s) {
+ $v = '';
+ $d = '';
+ $_s = split('=', $s, 2);
+ if (count($_s) > 1) {
+ $v = trim($_s[0]);
+ $d = trim($_s[1]);
+ } else {
+ $v = trim($_s[0]);
+ }
+ $auto .= sprintf('{ name: "%s", to: "%s" }, ',
+ Pluf_esc($d), Pluf_esc($v));
+ }
+ return substr($auto, 0, -1);
+ }
+}
+
+/**
+ * Display the summary of a download, then on a new line, display the
+ * list of labels.
+ *
+ * The summary of the download is linking to the download.
+ */
+function IDF_Views_Download_SummaryAndLabels($field, $down, $extra='')
+{
+ //$edit = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
+ // array($down->shortname, $down->id));
+ $tags = array();
+ foreach ($down->get_tags_list() as $tag) {
+ $tags[] = sprintf('%s', Pluf_esc((string) $tag));
+ }
+ $out = '';
+ if (count($tags)) {
+ $out = '
'.implode(', ', $tags).'';
+ }
+ return Pluf_esc($down->summary).$out;
+}
+
+function IDF_Views_Download_Size($field, $down)
+{
+ return Pluf_Utils::prettySize($down->$field);
+}
\ No newline at end of file
diff --git a/src/IDF/Views/Project.php b/src/IDF/Views/Project.php
index 32180eb..ef6ac62 100644
--- a/src/IDF/Views/Project.php
+++ b/src/IDF/Views/Project.php
@@ -82,7 +82,7 @@ class IDF_Views_Project
/**
* Administrate the issue tracking of a project.
*/
- public $adminIssueTracking_precond = array('IDF_Precondition::projectOwner');
+ public $adminIssues_precond = array('IDF_Precondition::projectOwner');
public function adminIssues($request, $match)
{
$prj = $request->project;
@@ -124,6 +124,49 @@ class IDF_Views_Project
}
/**
+ * Administrate the downloads of a project.
+ */
+ public $adminDownloads_precond = array('IDF_Precondition::projectOwner');
+ public function adminDownloads($request, $match)
+ {
+ $prj = $request->project;
+ $title = sprintf(__('%s Downloads Configuration'), (string) $prj);
+ $conf = new IDF_Conf();
+ $conf->setProject($prj);
+ if ($request->method == 'POST') {
+ $form = new IDF_Form_UploadConf($request->POST);
+ if ($form->isValid()) {
+ foreach ($form->cleaned_data as $key=>$val) {
+ $conf->setVal($key, $val);
+ }
+ $request->user->setMessage(__('The downloads configuration has been saved.'));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Project::adminDownloads',
+ array($prj->shortname));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+ } else {
+ $params = array();
+ $keys = array('labels_download_predefined', 'labels_download_one_max');
+ foreach ($keys as $key) {
+ $_val = $conf->getVal($key, false);
+ if ($_val !== false) {
+ $params[$key] = $_val;
+ }
+ }
+ if (count($params) == 0) {
+ $params = null; //Nothing in the db, so new form.
+ }
+ $form = new IDF_Form_UploadConf($params);
+ }
+ return Pluf_Shortcuts_RenderToResponse('admin/downloads.html',
+ array(
+ 'page_title' => $title,
+ 'form' => $form,
+ ),
+ $request);
+ }
+
+ /**
* Administrate the members of a project.
*/
public $adminMembers_precond = array('IDF_Precondition::projectOwner');
diff --git a/src/IDF/conf/views.php b/src/IDF/conf/views.php
index d47cc6a..10741f2 100644
--- a/src/IDF/conf/views.php
+++ b/src/IDF/conf/views.php
@@ -147,6 +147,24 @@ $ctl[] = array('regex' => '#^/p/(\w+)/source/download/(\w+)/$#',
'model' => 'IDF_Views_Source',
'method' => 'download');
+$ctl[] = array('regex' => '#^/p/(\w+)/downloads/$#',
+ 'base' => $base,
+ 'priority' => 4,
+ 'model' => 'IDF_Views_Download',
+ 'method' => 'index');
+
+$ctl[] = array('regex' => '#^/p/(\w+)/downloads/(\d+)/$#',
+ 'base' => $base,
+ 'priority' => 4,
+ 'model' => 'IDF_Views_Download',
+ 'method' => 'view');
+
+$ctl[] = array('regex' => '#^/p/(\w+)/downloads/create/$#',
+ 'base' => $base,
+ 'priority' => 4,
+ 'model' => 'IDF_Views_Download',
+ 'method' => 'submit');
+
// ---------- ADMIN --------------------------------------
@@ -162,6 +180,12 @@ $ctl[] = array('regex' => '#^/p/(\w+)/admin/issues/$#',
'model' => 'IDF_Views_Project',
'method' => 'adminIssues');
+$ctl[] = array('regex' => '#^/p/(\w+)/admin/downloads/$#',
+ 'base' => $base,
+ 'priority' => 4,
+ 'model' => 'IDF_Views_Project',
+ 'method' => 'adminDownloads');
+
$ctl[] = array('regex' => '#^/p/(\w+)/admin/members/$#',
'base' => $base,
'priority' => 4,
diff --git a/src/IDF/templates/admin/base.html b/src/IDF/templates/admin/base.html
index 3670329..0cae4d8 100644
--- a/src/IDF/templates/admin/base.html
+++ b/src/IDF/templates/admin/base.html
@@ -4,6 +4,7 @@
Instructions:
+List one status value per line in desired sort-order.
+Optionally, use an equals-sign to document the meaning of each status value.
+{/blocktrans} +{trans 'Number of files:'} {$downloads.nb_items}
+{/block} + diff --git a/src/IDF/templates/downloads/js-autocomplete.html b/src/IDF/templates/downloads/js-autocomplete.html new file mode 100644 index 0000000..0d00d55 --- /dev/null +++ b/src/IDF/templates/downloads/js-autocomplete.html @@ -0,0 +1,27 @@ +{if $isOwner or $isMember} + + + +{/if} diff --git a/src/IDF/templates/downloads/submit.html b/src/IDF/templates/downloads/submit.html new file mode 100644 index 0000000..663b39a --- /dev/null +++ b/src/IDF/templates/downloads/submit.html @@ -0,0 +1,57 @@ +{extends "downloads/base.html"} +{block docclass}yui-t3{assign $inSubmit=true}{/block} +{block body} +{if $form.errors} + +{/if} + + +{/block} +{block context} +{blocktrans}Each file must have a distinct name and file contents +cannot be changed, so be sure to include release numbers in each file +name.{/blocktrans}
+{trans 'Uploaded:'} {$file.creation_dtime|dateago} {blocktrans}by {$submitter}{/blocktrans}
++{trans 'Updated:'} {$file.modif_dtime|dateago}
+{assign $tags = $file.get_tags_list()}{if $tags.count()} +
+{trans 'Labels:'}
+{foreach $tags as $tag}
+{$tag.class}:{$tag.name}
+{/foreach}
+
{trans 'Labels:'}
-{foreach $issue.get_tags_list() as $tag}{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $tag.id, 'open')}
+{foreach $tags as $tag}{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $tag.id, 'open')}
{$tag.class}:{$tag.name}
{/foreach}