diff --git a/INSTALL.mdtext b/INSTALL.mdtext
index 7827f25..f5aeba2 100644
--- a/INSTALL.mdtext
+++ b/INSTALL.mdtext
@@ -6,9 +6,15 @@ the installation of InDefero by itself.
## PHP modules for indefero
-Indefero need the GD module for PHP. It's named "php5-gd" in debian.
+Indefero needs additional PHP modules to function correctly, namely
- $ apt-get install php5-gd
+ - gd (for graphic operations)
+ - zip (for upload archive processing)
+
+The package names of these modules might vary between distributions,
+for Debian they are
+
+ $ apt-get install php5-gd php5-zip
## Recommended Layout of the Files
diff --git a/NEWS.mdtext b/NEWS.mdtext
index c82a54b..bf489b0 100644
--- a/NEWS.mdtext
+++ b/NEWS.mdtext
@@ -1,15 +1,62 @@
-# InDefero 1.3 - xxx xxx xx xx:xx:xx UTC 201X
+# InDefero 1.3 - xxx xxx xx xx:xx 2011 UTC
+
+The development of this version of Indefero has been sponsored
+by the friendly folks from Scilab Instructions: The webhook URL setting specifies an URL to which a HTTP PUT"
+"strong>\n"
+"request is sent after a new download has been added or to which a HTTP "
+"POST\n"
+"request is sent after an existing download has been updated.\n"
+"If this field is empty, notifications are disabled. Only properly-escaped HTTP URLs are supported, for "
+"example: In addition, the URL may contain the following \"%\" notation, which\n"
+"will be replaced with specific project values for each download: For example, updating download 123 of project 'my-project' with\n"
+"web hook URL The webhook URL setting specifies a URL to which a HTTP POST\n"
-"request is sent after each repository commit. If this field is empty,\n"
-"notifications are disabled. The webhook URL setting specifies an URL to which a HTTP \n"
+"%%hook_request_method%% request is sent after each "
+"repository\n"
+"commit. If this field is empty, notifications are disabled. Only properly-escaped HTTP URLs are supported, for "
"example: In addition, the URL may contain the following \"%\" notation, which\n"
"will be replaced with specific project values for each commit: For example, committing revision 123 to project 'my-project' with\n"
-"post-commit URL http://mydomain.com/%p/%r would send a request to\n"
-"http://mydomain.com/my-project/123.'.
@@ -150,14 +150,14 @@ class IDF_Review_Patch extends Pluf_Model
$ic = (in_array($review->status, $request->project->getTagIdsByStatus('closed'))) ? 'issue-c' : 'issue-o';
$out .= sprintf(__('Review %3$d, %4$s'), $url, $ic, $review->id, Pluf_esc($review->summary)).' ';
$out .= "\n".' ';
+
- '.$m[1].'';
+ return '
'.$m[1].'';
}
if (!$this->request->rights['hasWikiAccess'] or $pages->count() == 0) {
return $m[1];
}
- return ''.$m[1].'';
+ return ''.$m[1].'';
+ }
+
+ function callbackWikiResource($m)
+ {
+ @list($match, $resourceName, $opts) = $m;
+
+ if (!$this->request->rights['hasWikiAccess']) {
+ return ''.$match.'';
+ }
+
+ $sql = new Pluf_SQL('project=%s AND title=%s',
+ array($this->project->id, $resourceName));
+ $resources = Pluf::factory('IDF_Wiki_Resource')->getList(array('filter'=>$sql->gen()));
+
+ if ($resources->count() == 0) {
+ if ($this->request->user->isAnonymous()) {
+ return ''.$match.'';
+ }
+
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::createResource',
+ array($this->project->shortname),
+ array('name' => $resourceName));
+ return '
'.
+ ''.$match.'';
+ }
+
+ // by default, render the most recent revision
+ $resourceRevision = $resources[0]->get_current_revision();
+
+ list($urlConf, $urlMatches) = $this->request->view;
+
+ // if we currently look at an existing wiki page, look up its name and find the proper resource (if any)
+ if ($urlConf['model'] == 'IDF_Views_Wiki' && $urlConf['method'] == 'viewPage') {
+ $sql = new Pluf_SQL('project=%s AND title=%s',
+ array($this->project->id, $urlMatches[2]));
+ $pages = Pluf::factory('IDF_Wiki_Page')->getList(array('filter'=>$sql->gen()));
+ if ($pages->count() == 0) throw new Exception('page not found');
+ $pageRevision = $pages[0]->get_current_revision();
+
+ // if we look at an old version of the page, figure out the resource version back then
+ if (isset($this->request->GET['rev']) and preg_match('/^[0-9]+$/', $this->request->GET['rev'])) {
+ $pageRevision = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_PageRevision',
+ $this->request->GET['rev']);
+ // this is actually an invariant since we came so far looking at
+ // and rendering the old revision already
+ if ($pageRevision == null) {
+ throw new Exception('page revision with id '.$this->request->GET['rev'].' not found');
+ }
+ }
+
+ $sql = new Pluf_SQL('wikiresource=%s AND idf_wiki_pagerevision_id=%s',
+ array($resources[0]->id, $pageRevision->id));
+ $resourceRevision = Pluf::factory('IDF_Wiki_ResourceRevision')->getOne(
+ array('filter' => $sql->gen(), 'view' => 'join_pagerevision'));
+
+ if ($resourceRevision == null) {
+ return ''.$match.'';
+ }
+ }
+
+ $validOpts = array(
+ 'align' => '/^(left|right|center)$/',
+ 'width' => '/^\d+(%|px|em)?$/',
+ 'height' => '/^\d+(%|px|em)?$/',
+ 'preview' => '/^yes|no$/',
+ 'title' => '/.+/',
+ );
+
+ $parsedOpts = array();
+ // FIXME: no support for escaping yet in place
+ $opts = preg_split('/\s*,\s*/', $opts, -1, PREG_SPLIT_NO_EMPTY);
+ foreach ((array)@$opts as $opt)
+ {
+ list($key, $value) = preg_split('/\s*=\s*/', $opt, 2);
+ if (!array_key_exists($key, $validOpts)) {
+ continue;
+ }
+ if (!preg_match($validOpts[$key], $value)) {
+ continue;
+ }
+ $parsedOpts[$key] = $value;
+ }
+
+ return $resourceRevision->render($parsedOpts);
}
function callbackEmbeddedDoc($m)
diff --git a/src/IDF/Template/MarkdownForge.php b/src/IDF/Template/MarkdownForge.php
new file mode 100644
index 0000000..1169095
--- /dev/null
+++ b/src/IDF/Template/MarkdownForge.php
@@ -0,0 +1,118 @@
+request = $request;
+ $filter = new IDF_Template_MarkdownPrefilter();
+ $text = $filter->go(Pluf_Text_MarkDown_parse($text));
+
+ // replace {}-macros with the corresponding template rendering
+ echo IDF_Template_safePregReplace('#\{(\w+)(?:,\s*([^\}]+))?\}#im',
+ array($this, 'callbackMacros'),
+ $text);
+ }
+
+ public function callbackMacros($matches)
+ {
+ @list(, $macro, $opts) = $matches;
+ $known_macros = array('projectlist');
+ if (!in_array($macro, $known_macros)) {
+ return $matches[0];
+ }
+ $callbackName = 'callback'.ucfirst(strtolower($macro)).'Macro';
+ return $this->callbackProjectlistMacro($opts);
+ }
+
+ public function callbackProjectlistMacro($opts)
+ {
+ $validOpts = array(
+ 'label' => '/^\d+|(\w+:)?\w+$/',
+ 'order' => '/^name|activity$/',
+ 'limit' => '/^\d+$/',
+ );
+
+ $parsedOpts = array();
+ // FIXME: no support for escaping yet in place
+ $opts = preg_split('/\s*,\s*/', $opts, -1, PREG_SPLIT_NO_EMPTY);
+ foreach ((array)@$opts as $opt)
+ {
+ list($key, $value) = preg_split('/\s*=\s*/', $opt, 2);
+ if (!array_key_exists($key, $validOpts)) {
+ continue;
+ }
+ if (!preg_match($validOpts[$key], $value)) {
+ continue;
+ }
+ $parsedOpts[$key] = $value;
+ }
+
+ $tag = false;
+ if (!empty($parsedOpts['label'])) {
+ if (is_numeric($parsedOpts['label'])) {
+ $tag = Pluf::factory('IDF_Tag')->get($parsedOpts['label']);
+ } else {
+ @list($class, $name) = preg_split('/:/', $parsedOpts['label'], 2);
+ if (empty($name)) {
+ $name = $class;
+ $class = IDF_TAG_DEFAULT_CLASS;
+ }
+ $sql = new Pluf_SQL('class=%s AND lcname=%s AND project=0',
+ array(strtolower($class), mb_strtolower($name)));
+ $tag = Pluf::factory('IDF_Tag')->getOne(array('filter' => $sql->gen()));
+ }
+ // ignore non-global tags
+ if ($tag !== false && $tag->project > 0) {
+ $tag = false;
+ }
+ }
+
+ $order = 'name';
+ if (!empty($parsedOpts['order'])) {
+ $order = $parsedOpts['order'];
+ }
+
+ $projects = IDF_Views::getProjects($this->request->user, $tag, $order);
+ if (!empty($parsedOpts['limit']) && $parsedOpts['limit'] < count($projects)) {
+ // there is no array_slice on ArrayObject, do'h!
+ $projectsCopy = array();
+ for ($i=0; $i<$parsedOpts['limit']; ++$i)
+ $projectsCopy[] = $projects[$i];
+ $projects = $projectsCopy;
+ }
+
+ $tmpl = new Pluf_Template('idf/project-list.html');
+ $context = new Pluf_Template_Context(array(
+ 'projects' => $projects,
+ 'order' => 'name',
+ ));
+ return $tmpl->render($context);
+ }
+}
+
diff --git a/src/IDF/Upload.php b/src/IDF/Upload.php
index b683156..2fa7aec 100644
--- a/src/IDF/Upload.php
+++ b/src/IDF/Upload.php
@@ -234,31 +234,91 @@ class IDF_Upload extends Pluf_Model
*/
public function notify($conf, $create=true)
{
- if ('' == $conf->getVal('downloads_notification_email', '')) {
- return;
- }
- $current_locale = Pluf_Translation::getLocale();
- $langs = Pluf::f('languages', array('en'));
- Pluf_Translation::loadSetLocale($langs[0]);
+ $project = $this->get_project();
+ $url = str_replace(array('%p', '%d'),
+ array($project->shortname, $this->id),
+ $conf->getVal('upload_webhook_url', ''));
- $context = new Pluf_Template_Context(
- array('file' => $this,
- 'urlfile' => $this->getAbsoluteUrl($this->get_project()),
- 'project' => $this->get_project(),
- 'tags' => $this->get_tags_list(),
- ));
- $tmpl = new Pluf_Template('idf/downloads/download-created-email.txt');
- $text_email = $tmpl->render($context);
- $addresses = explode(',', $conf->getVal('downloads_notification_email'));
- foreach ($addresses as $address) {
- $email = new Pluf_Mail(Pluf::f('from_email'),
+ $tags = array();
+ foreach ($this->get_tags_list() as $tag) {
+ $tags[] = $tag->class.':'.$tag->name;
+ }
+
+ $submitter = $this->get_submitter();
+ $payload = array(
+ 'to_send' => array(
+ 'project' => $project->shortname,
+ 'id' => $this->id,
+ 'summary' => $this->summary,
+ 'changelog' => $this->changelog,
+ 'filename' => $this->file,
+ 'filesize' => $this->filesize,
+ 'md5sum' => $this->md5,
+ 'submitter_login' => $submitter->login,
+ 'submitter_email' => $submitter->email,
+ 'tags' => $tags,
+ ),
+ 'project_id' => $project->id,
+ 'authkey' => $project->getWebHookKey(),
+ 'url' => $url,
+ );
+
+ if ($create === true) {
+ $payload['method'] = 'PUT';
+ $payload['to_send']['creation_date'] = $this->creation_dtime;
+ } else {
+ $payload['method'] = 'POST';
+ $payload['to_send']['update_date'] = $this->modif_dtime;
+ }
+
+ $item = new IDF_Queue();
+ $item->type = 'upload';
+ $item->payload = $payload;
+ $item->create();
+
+ $current_locale = Pluf_Translation::getLocale();
+
+ $from_email = Pluf::f('from_email');
+ $messageId = '<'.md5('upload'.$this->id.md5(Pluf::f('secret_key'))).'@'.Pluf::f('mail_host', 'localhost').'>';
+ $recipients = $project->getNotificationRecipientsForTab('downloads');
+
+ foreach ($recipients as $address => $language) {
+
+ if ($this->get_submitter()->email === $address) {
+ continue;
+ }
+
+ Pluf_Translation::loadSetLocale($language);
+
+ $context = new Pluf_Template_Context(array(
+ 'file' => $this,
+ 'urlfile' => $this->getAbsoluteUrl($project),
+ 'project' => $project,
+ 'tags' => $this->get_tags_list(),
+ ));
+
+ $tplfile = 'idf/downloads/download-created-email.txt';
+ $subject = __('New download - %1$s (%2$s)');
+ $headers = array('Message-ID' => $messageId);
+ if (!$create) {
+ $tplfile = 'idf/downloads/download-updated-email.txt';
+ $subject = __('Updated download - %1$s (%2$s)');
+ $headers = array('References' => $messageId);
+ }
+
+ $tmpl = new Pluf_Template($tplfile);
+ $text_email = $tmpl->render($context);
+
+ $email = new Pluf_Mail($from_email,
$address,
- sprintf(__('New download - %1$s (%2$s)'),
+ sprintf($subject,
$this->summary,
- $this->get_project()->shortname));
+ $project->shortname));
$email->addTextMessage($text_email);
+ $email->addHeaders($headers);
$email->sendMail();
}
+
Pluf_Translation::loadSetLocale($current_locale);
}
}
diff --git a/src/IDF/Views.php b/src/IDF/Views.php
index beca428..85dfa9b 100644
--- a/src/IDF/Views.php
+++ b/src/IDF/Views.php
@@ -32,20 +32,67 @@ Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
class IDF_Views
{
/**
- * List all the projects managed by InDefero.
- *
- * Only the public projects are listed or the private with correct
- * rights.
+ * The index view.
*/
- public function index($request, $match, $api=false)
+ public function index($request, $match)
{
- $projects = self::getProjects($request->user);
- $stats = self::getProjectsStatistics ($projects);
-
- if ($api == true) return $projects;
- return Pluf_Shortcuts_RenderToResponse('idf/index.html',
+ $forge = IDF_Forge::instance();
+ if (!$forge->isCustomForgePageEnabled()) {
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views::listProjects');
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+
+ return Pluf_Shortcuts_RenderToResponse('idf/index.html',
+ array('page_title' => __('Welcome'),
+ 'content' => $forge->getCustomForgePageContent(),
+ ),
+ $request);
+ }
+
+ /**
+ * List all projects unfiltered
+ *
+ * @param unknown_type $request
+ * @param unknown_type $match
+ * @return Pluf_HTTP_Response
+ */
+ public function listProjects($request, $match)
+ {
+ $match = array('', 'all', 'name');
+ return $this->listProjectsByLabel($request, $match);
+ }
+
+ /**
+ * List projects, optionally filtered by label
+ *
+ * @param unknown_type $request
+ * @param unknown_type $match
+ * @return Pluf_HTTP_Response
+ */
+ public function listProjectsByLabel($request, $match)
+ {
+ list(, $tagId, $order) = $match;
+
+ $tag = false;
+ if ($tagId !== 'all') {
+ $tag = Pluf::factory('IDF_Tag')->get($match[1]);
+ // ignore non-global tags
+ if ($tag !== false && $tag->project > 0) {
+ $tag = false;
+ }
+ }
+ $order = in_array($order, array('name', 'activity')) ? $order : 'name';
+
+ $projects = self::getProjects($request->user, $tag, $order);
+ $stats = self::getProjectsStatistics($projects);
+ $projectLabels = IDF_Forge::instance()->getProjectLabelsWithCounts();
+
+ return Pluf_Shortcuts_RenderToResponse('idf/listProjects.html',
array('page_title' => __('Projects'),
'projects' => $projects,
+ 'projectLabels' => $projectLabels,
+ 'tag' => $tag,
+ 'order' => $order,
'stats' => new Pluf_Template_ContextVars($stats)),
$request);
}
@@ -55,7 +102,7 @@ class IDF_Views
*/
public function login($request, $match)
{
- if (isset($request->POST['action'])
+ if (isset($request->POST['action'])
and $request->POST['action'] == 'new-user') {
$login = (isset($request->POST['login'])) ? $request->POST['login'] : '';
$url = Pluf_HTTP_URL_urlForView('IDF_Views::register', array(),
@@ -91,7 +138,7 @@ class IDF_Views
$params = array('request'=>$request);
if ($request->method == 'POST') {
$form = new IDF_Form_Register(array_merge(
- (array)$request->POST,
+ (array)$request->POST,
(array)$request->FILES
), $params);
if ($form->isValid()) {
@@ -108,7 +155,7 @@ class IDF_Views
$context = new Pluf_Template_Context(array());
$tmpl = new Pluf_Template('idf/terms.html');
$terms = Pluf_Template::markSafe($tmpl->render($context));
- return Pluf_Shortcuts_RenderToResponse('idf/register/index.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/register/index.html',
array('page_title' => $title,
'form' => $form,
'terms' => $terms),
@@ -133,7 +180,7 @@ class IDF_Views
} else {
$form = new IDF_Form_RegisterInputKey();
}
- return Pluf_Shortcuts_RenderToResponse('idf/register/inputkey.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/register/inputkey.html',
array('page_title' => $title,
'form' => $form),
$request);
@@ -168,7 +215,7 @@ class IDF_Views
$request->session->clear();
$request->session->setData('login_time', gmdate('Y-m-d H:i:s'));
$user->last_login = gmdate('Y-m-d H:i:s');
- $user->update();
+ $user->update();
$request->user->setMessage(__('Welcome! You can now participate in the life of your project of choice.'));
$url = Pluf_HTTP_URL_urlForView('IDF_Views::index');
return new Pluf_HTTP_Response_Redirect($url);
@@ -176,7 +223,7 @@ class IDF_Views
} else {
$form = new IDF_Form_RegisterConfirmation(null, $extra);
}
- return Pluf_Shortcuts_RenderToResponse('idf/register/confirmation.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/register/confirmation.html',
array('page_title' => $title,
'new_user' => $user,
'form' => $form),
@@ -213,7 +260,7 @@ class IDF_Views
/**
* If the key is valid, provide a nice form to reset the password
- * and automatically login the user.
+ * and automatically login the user.
*
* This is also firing the password change event for the plugins.
*/
@@ -238,7 +285,7 @@ class IDF_Views
$request->session->clear();
$request->session->setData('login_time', gmdate('Y-m-d H:i:s'));
$user->last_login = gmdate('Y-m-d H:i:s');
- $user->update();
+ $user->update();
$request->user->setMessage(__('Welcome back! Next time, you can use your broswer options to remember the password.'));
$url = Pluf_HTTP_URL_urlForView('IDF_Views::index');
return new Pluf_HTTP_Response_Redirect($url);
@@ -246,12 +293,12 @@ class IDF_Views
} else {
$form = new IDF_Form_PasswordReset(null, $extra);
}
- return Pluf_Shortcuts_RenderToResponse('idf/user/passrecovery.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/user/passrecovery.html',
array('page_title' => $title,
'new_user' => $user,
'form' => $form),
$request);
-
+
}
/**
@@ -270,7 +317,7 @@ class IDF_Views
} else {
$form = new IDF_Form_PasswordInputKey();
}
- return Pluf_Shortcuts_RenderToResponse('idf/user/passrecovery-inputkey.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/user/passrecovery-inputkey.html',
array('page_title' => $title,
'form' => $form),
$request);
@@ -283,7 +330,23 @@ class IDF_Views
{
$title = __('Here to Help You!');
$projects = self::getProjects($request->user);
- return Pluf_Shortcuts_RenderToResponse('idf/faq.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/faq.html',
+ array(
+ 'page_title' => $title,
+ 'projects' => $projects,
+ ),
+ $request);
+
+ }
+
+ /**
+ * Download archive FAQ.
+ */
+ public function faqArchiveFormat($request, $match)
+ {
+ $title = __('InDefero Upload Archive Format');
+ $projects = self::getProjects($request->user);
+ return Pluf_Shortcuts_RenderToResponse('idf/faq-archive-format.html',
array(
'page_title' => $title,
'projects' => $projects,
@@ -299,7 +362,7 @@ class IDF_Views
{
$title = __('InDefero API (Application Programming Interface)');
$projects = self::getProjects($request->user);
- return Pluf_Shortcuts_RenderToResponse('idf/faq-api.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/faq-api.html',
array(
'page_title' => $title,
'projects' => $projects,
@@ -309,45 +372,59 @@ class IDF_Views
}
/**
- * Returns a list of projects accessible for the user.
+ * Returns a list of projects accessible for the user and optionally filtered by tag.
*
* @param Pluf_User
+ * @param IDF_Tag
* @return ArrayObject IDF_Project
*/
- public static function getProjects($user)
+ public static function getProjects($user, $tag = false, $order = 'name')
{
$db =& Pluf::db();
$false = Pluf_DB_BooleanToDb(false, $db);
- if ($user->isAnonymous()) {
- $sql = sprintf('%s=%s', $db->qn('private'), $false);
- return Pluf::factory('IDF_Project')->getList(array('filter'=> $sql,
- 'order' => 'name ASC'));
+ $sql = new Pluf_SQL(1);
+ if ($tag !== false) {
+ $sql->SAnd(new Pluf_SQL('idf_tag_id=%s', $tag->id));
}
- if ($user->administrator) {
- return Pluf::factory('IDF_Project')->getList(array('order' => 'name ASC'));
- }
- // grab the list of projects where the user is admin, member
- // or authorized
- $perms = array(
- Pluf_Permission::getFromString('IDF.project-member'),
- Pluf_Permission::getFromString('IDF.project-owner'),
- Pluf_Permission::getFromString('IDF.project-authorized-user')
- );
- $sql = new Pluf_SQL("model_class='IDF_Project' AND owner_class='Pluf_User' AND owner_id=%s AND negative=".$false, $user->id);
- $rows = Pluf::factory('Pluf_RowPermission')->getList(array('filter' => $sql->gen()));
-
- $sql = sprintf('%s=%s', $db->qn('private'), $false);
- if ($rows->count() > 0) {
- $ids = array();
- foreach ($rows as $row) {
- $ids[] = $row->model_id;
+
+ if ($user->isAnonymous())
+ {
+ $authSql = new Pluf_SQL('private=%s', $false);
+ $sql->SAnd($authSql);
+ } else
+ if (!$user->administrator) {
+ // grab the list of projects where the user is admin,
+ // member or authorized
+ $perms = array(
+ Pluf_Permission::getFromString('IDF.project-member'),
+ Pluf_Permission::getFromString('IDF.project-owner'),
+ Pluf_Permission::getFromString('IDF.project-authorized-user')
+ );
+ $permSql = new Pluf_SQL("model_class='IDF_Project' AND owner_class='Pluf_User' AND owner_id=%s AND negative=".$false, $user->id);
+ $rows = Pluf::factory('Pluf_RowPermission')->getList(array('filter' => $permSql->gen()));
+
+ $authSql = new Pluf_SQL('private=%s', $false);
+ if ($rows->count() > 0) {
+ $ids = array();
+ foreach ($rows as $row) {
+ $ids[] = $row->model_id;
+ }
+ $authSql->SOr(new Pluf_SQL(sprintf($db->pfx.'idf_projects.id IN (%s)', implode(', ', $ids))));
}
- $sql .= sprintf(' OR id IN (%s)', implode(', ', $ids));
+ $sql->SAnd($authSql);
}
- return Pluf::factory('IDF_Project')->getList(array('filter' => $sql,
- 'order' => 'name ASC'));
+
+ $orderTypes = array(
+ 'name' => 'name ASC',
+ 'activity' => 'value DESC, name ASC',
+ );
+ return Pluf::factory('IDF_Project')->getList(array(
+ 'filter'=> $sql->gen(),
+ 'view' => 'join_activities_and_tags',
+ 'order' => $orderTypes[$order],
+ ));
}
-
+
/**
* Returns statistics on a list of projects.
*
@@ -362,25 +439,22 @@ class IDF_Views
'issues' => 0,
'docpages' => 0,
'commits' => 0);
-
+
// Count for each projects
foreach ($projects as $p) {
- $pstats = $p->getStats ();
+ $pstats = $p->getStats();
$forgestats['downloads'] += $pstats['downloads'];
$forgestats['reviews'] += $pstats['reviews'];
$forgestats['issues'] += $pstats['issues'];
$forgestats['docpages'] += $pstats['docpages'];
$forgestats['commits'] += $pstats['commits'];
}
-
- // Count projects
- $forgestats['projects'] = count($projects);
// Count members
$sql = new Pluf_SQL('first_name != %s', array('---'));
$forgestats['members'] = Pluf::factory('Pluf_User')
->getCount(array('filter' => $sql->gen()));
-
+
return $forgestats;
}
}
diff --git a/src/IDF/Views/Admin.php b/src/IDF/Views/Admin.php
index 60b160e..7e78698 100644
--- a/src/IDF/Views/Admin.php
+++ b/src/IDF/Views/Admin.php
@@ -32,20 +32,40 @@ Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
class IDF_Views_Admin
{
/**
- * Home page of the administration.
- *
- * It should provide an overview of the forge status.
+ * Start page of the administration.
*/
- public $home_precond = array('Pluf_Precondition::staffRequired');
- public function home($request, $match)
+ public $forge_precond = array('Pluf_Precondition::staffRequired');
+ public function forge($request, $match)
{
$title = __('Forge Management');
- return Pluf_Shortcuts_RenderToResponse('idf/gadmin/home.html',
+ $forge = IDF_Forge::instance();
+ if ($request->method == 'POST') {
+ $form = new IDF_Form_Admin_ForgeConf($request->POST);
+ if ($form->isValid()) {
+ $forge->setCustomForgePageEnabled($form->cleaned_data['enabled']);
+ $forge->setCustomForgePageContent($form->cleaned_data['content']);
+ $request->user->setMessage(__('The forge configuration has been saved.'));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Admin::forge');
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+ } else {
+ $params = array();
+ $params['enabled'] = $forge->isCustomForgePageEnabled();
+ if (($content = $forge->getCustomForgePageContent(false)) !== false) {
+ $params['content'] = $content;
+ }
+ if (count($params) == 0) {
+ $params = null; //Nothing in the db, so new form.
+ }
+ $form = new IDF_Form_Admin_ForgeConf($params);
+ }
+ return Pluf_Shortcuts_RenderToResponse('idf/gadmin/forge/index.html',
array(
- 'page_title' => $title,
- ),
+ 'page_title' => $title,
+ 'form' => $form,
+ ),
$request);
- }
+ }
/**
* Projects overview.
@@ -81,6 +101,40 @@ class IDF_Views_Admin
$request);
}
+ /**
+ * Administrate the labels of a project.
+ */
+ public $projectLabels_precond = array('Pluf_Precondition::staffRequired');
+ public function projectLabels($request, $match)
+ {
+ $title = __('Project Labels');
+ $forge = IDF_Forge::instance();
+ if ($request->method == 'POST') {
+ $form = new IDF_Form_Admin_LabelConf($request->POST);
+ if ($form->isValid()) {
+ $forge->setProjectLabels($form->cleaned_data['project_labels']);
+ $request->user->setMessage(__('The label configuration has been saved.'));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Admin::projectLabels');
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+ } else {
+ $params = array();
+ if (($labels = $forge->getProjectLabels(false)) !== false) {
+ $params['project_labels'] = $labels;
+ }
+ if (count($params) == 0) {
+ $params = null; //Nothing in the db, so new form.
+ }
+ $form = new IDF_Form_Admin_LabelConf($params);
+ }
+ return Pluf_Shortcuts_RenderToResponse('idf/gadmin/projects/labels.html',
+ array(
+ 'page_title' => $title,
+ 'form' => $form,
+ ),
+ $request);
+ }
+
/**
* Edition of a project.
*
@@ -106,12 +160,16 @@ class IDF_Views_Admin
} else {
$form = new IDF_Form_Admin_ProjectUpdate(null, $params);
}
+ $arrays = IDF_Views_Project::autoCompleteArrays();
return Pluf_Shortcuts_RenderToResponse('idf/gadmin/projects/update.html',
- array(
- 'page_title' => $title,
- 'project' => $project,
- 'form' => $form,
- ),
+ array_merge(
+ array(
+ 'page_title' => $title,
+ 'project' => $project,
+ 'form' => $form,
+ ),
+ $arrays
+ ),
$request);
}
@@ -139,12 +197,17 @@ class IDF_Views_Admin
$form = new IDF_Form_Admin_ProjectCreate(null, $extra);
}
$base = Pluf::f('url_base').Pluf::f('idf_base').'/p/';
+
+ $arrays = IDF_Views_Project::autoCompleteArrays();
return Pluf_Shortcuts_RenderToResponse('idf/gadmin/projects/create.html',
- array(
- 'page_title' => $title,
- 'form' => $form,
- 'base_url' => $base,
- ),
+ array_merge(
+ array(
+ 'page_title' => $title,
+ 'form' => $form,
+ 'base_url' => $base,
+ ),
+ $arrays
+ ),
$request);
}
diff --git a/src/IDF/Views/Api.php b/src/IDF/Views/Api.php
index ba78dec..c0e488d 100644
--- a/src/IDF/Views/Api.php
+++ b/src/IDF/Views/Api.php
@@ -29,7 +29,7 @@
* JSON instead of HTML.
*
* A special precondition is used to set the $request->user from the
- * _login, _hash and _salt parameters.
+ * _login, _hash and _salt parameters.
*/
class IDF_Views_Api
{
@@ -90,17 +90,16 @@ class IDF_Views_Api
* List all the projects
*/
public $projectIndex_precond = array('IDF_Precondition::apiSetUser');
-
+
public function projectIndex($request, $match)
{
- $view = new IDF_Views();
- $projects = $view->index($request, $match, true);
-
+ $projects = IDF_Views::getProjects($request->user);
+
$data = array();
foreach ($projects as $p) {
$data[] = array("shortname" => $p->shortname, "name" => $p->name, "shortdesc" => $p->shortdesc, "private" => $p->private);
}
-
+
$out = array();
$out['message'] = 'success';
$out['projects'] = $data;
diff --git a/src/IDF/Views/Download.php b/src/IDF/Views/Download.php
index 5fb49e8..637e25e 100644
--- a/src/IDF/Views/Download.php
+++ b/src/IDF/Views/Download.php
@@ -205,7 +205,8 @@ class IDF_Views_Download
$path = $upload->getFullPath();
$mime = IDF_FileUtil::getMimeType($path);
$render = new Pluf_HTTP_Response_File($path, $mime[0]);
- $render->headers["Content-MD5"] = $upload->md5;
+ $render->headers['Content-MD5'] = $upload->md5;
+ $render->headers['Content-Disposition'] = 'attachment; filename="'.$upload->file.'"';
return $render;
}
@@ -224,11 +225,11 @@ class IDF_Views_Download
}
/**
- * Submit a new file for download.
+ * Create a new file for download.
*/
- public $submit_precond = array('IDF_Precondition::accessDownloads',
+ public $create_precond = array('IDF_Precondition::accessDownloads',
'IDF_Precondition::projectMemberOrOwner');
- public function submit($request, $match)
+ public function create($request, $match)
{
$prj = $request->project;
$title = __('New Download');
@@ -250,7 +251,7 @@ class IDF_Views_Download
array('project' => $prj,
'user' => $request->user));
}
- return Pluf_Shortcuts_RenderToResponse('idf/downloads/submit.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/downloads/create.html',
array(
'auto_labels' => self::autoCompleteArrays($prj),
'page_title' => $title,
@@ -259,6 +260,39 @@ class IDF_Views_Download
$request);
}
+ /**
+ * Create new downloads from an uploaded archive.
+ */
+ public $createFromArchive_precond = array('IDF_Precondition::accessDownloads',
+ 'IDF_Precondition::projectMemberOrOwner');
+ public function createFromArchive($request, $match)
+ {
+ $prj = $request->project;
+ $title = __('New Downloads from Archive');
+ if ($request->method == 'POST') {
+ $form = new IDF_Form_UploadArchive(array_merge($request->POST, $request->FILES),
+ array('project' => $prj,
+ 'user' => $request->user));
+ if ($form->isValid()) {
+ $upload = $form->save();
+ $request->user->setMessage(__('The archive has been uploaded and processed.'));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::index',
+ array($prj->shortname));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+ } else {
+ $form = new IDF_Form_UploadArchive(null,
+ array('project' => $prj,
+ 'user' => $request->user));
+ }
+ return Pluf_Shortcuts_RenderToResponse('idf/downloads/createFromArchive.html',
+ array(
+ 'page_title' => $title,
+ 'form' => $form,
+ ),
+ $request);
+ }
+
/**
* Create the autocomplete arrays for the little AJAX stuff.
*/
diff --git a/src/IDF/Views/Project.php b/src/IDF/Views/Project.php
index 11c08f4..e83fc93 100644
--- a/src/IDF/Views/Project.php
+++ b/src/IDF/Views/Project.php
@@ -68,7 +68,7 @@ class IDF_Views_Project
$pages = array();
if ($request->rights['hasWikiAccess']) {
$tags = IDF_Views_Wiki::getWikiTags($prj);
- $pages = $tags[0]->get_idf_wikipage_list();
+ $pages = $tags[0]->get_idf_wiki_page_list();
}
return Pluf_Shortcuts_RenderToResponse('idf/project/home.html',
array(
@@ -131,8 +131,10 @@ class IDF_Views_Project
}
if (true === IDF_Precondition::accessWiki($request) &&
($model_filter == 'all' || $model_filter == 'documents')) {
- $classes[] = '\'IDF_WikiPage\'';
- $classes[] = '\'IDF_WikiRevision\'';
+ $classes[] = '\'IDF_Wiki_Page\'';
+ $classes[] = '\'IDF_Wiki_PageRevision\'';
+ $classes[] = '\'IDF_Wiki_Resource\'';
+ $classes[] = '\'IDF_Wiki_ResourceRevision\'';
}
if (true === IDF_Precondition::accessReview($request) &&
($model_filter == 'all' || $model_filter == 'reviews')) {
@@ -305,17 +307,21 @@ class IDF_Views_Project
return new Pluf_HTTP_Response_Redirect($url);
}
} else {
- $form = new IDF_Form_ProjectConf($prj->getData(), $extra);
+ $form = new IDF_Form_ProjectConf(null, $extra);
}
$logo = $prj->getConf()->getVal('logo');
+ $arrays = self::autoCompleteArrays();
return Pluf_Shortcuts_RenderToResponse('idf/admin/summary.html',
- array(
- 'page_title' => $title,
- 'form' => $form,
- 'project' => $prj,
- 'logo' => $logo,
- ),
+ array_merge(
+ array(
+ 'page_title' => $title,
+ 'form' => $form,
+ 'project' => $prj,
+ 'logo' => $logo,
+ ),
+ $arrays
+ ),
$request);
}
@@ -375,8 +381,11 @@ class IDF_Views_Project
$title = sprintf(__('%s Downloads Configuration'), (string) $prj);
$conf = new IDF_Conf();
$conf->setProject($prj);
+ $extra = array(
+ 'conf' => $conf,
+ );
if ($request->method == 'POST') {
- $form = new IDF_Form_UploadConf($request->POST);
+ $form = new IDF_Form_UploadConf($request->POST, $extra);
if ($form->isValid()) {
foreach ($form->cleaned_data as $key=>$val) {
$conf->setVal($key, $val);
@@ -388,7 +397,7 @@ class IDF_Views_Project
}
} else {
$params = array();
- $keys = array('labels_download_predefined', 'labels_download_one_max');
+ $keys = array('labels_download_predefined', 'labels_download_one_max', 'upload_webhook_url');
foreach ($keys as $key) {
$_val = $conf->getVal($key, false);
if ($_val !== false) {
@@ -398,12 +407,13 @@ class IDF_Views_Project
if (count($params) == 0) {
$params = null; //Nothing in the db, so new form.
}
- $form = new IDF_Form_UploadConf($params);
+ $form = new IDF_Form_UploadConf($params, $extra);
}
return Pluf_Shortcuts_RenderToResponse('idf/admin/downloads.html',
array(
'page_title' => $title,
'form' => $form,
+ 'hookkey' => $prj->getWebHookKey(),
),
$request);
}
@@ -504,21 +514,24 @@ class IDF_Views_Project
}
}
$form->save(); // Save the authorized users.
- $request->user->setMessage(__('The project tabs access rights have been saved.'));
+ $request->user->setMessage(__('The project tabs access rights and notification settings have been saved.'));
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Project::adminTabs',
array($prj->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
} else {
$params = array();
- $keys = array('downloads_access_rights', 'source_access_rights',
- 'issues_access_rights', 'review_access_rights',
- 'wiki_access_rights',
- 'downloads_notification_email',
- 'review_notification_email',
- 'wiki_notification_email',
- 'source_notification_email',
- 'issues_notification_email');
+ $sections = array('downloads', 'wiki', 'source', 'issues', 'review');
+ $keys = array();
+
+ foreach ($sections as $section) {
+ $keys[] = $section.'_access_rights';
+ $keys[] = $section.'_notification_owners_enabled';
+ $keys[] = $section.'_notification_members_enabled';
+ $keys[] = $section.'_notification_email_enabled';
+ $keys[] = $section.'_notification_email';
+ }
+
foreach ($keys as $key) {
$_val = $request->conf->getVal($key, false);
if ($_val !== false) {
@@ -590,6 +603,10 @@ class IDF_Views_Project
'mtn' => __('monotone'),
);
$repository_type = $options[$scm];
+ $hook_request_method = 'PUT';
+ if (Pluf::f('webhook_processing','') === 'compat') {
+ $hook_request_method = 'POST';
+ }
return Pluf_Shortcuts_RenderToResponse('idf/admin/source.html',
array(
'remote_svn' => $remote_svn,
@@ -598,8 +615,41 @@ class IDF_Views_Project
'repository_size' => $prj->getRepositorySize(),
'page_title' => $title,
'form' => $form,
- 'hookkey' => $prj->getPostCommitHookKey(),
+ 'hookkey' => $prj->getWebHookKey(),
+ 'hook_request_method' => $hook_request_method,
),
$request);
}
+
+ /**
+ * Create the autocomplete arrays for the little AJAX stuff.
+ */
+ public static function autoCompleteArrays()
+ {
+ $forge = IDF_Forge::instance();
+ $labels = $forge->getProjectLabels(IDF_Form_Admin_LabelConf::init_project_labels);
+
+ $auto = array('auto_labels' => '');
+ $auto_raw = array('auto_labels' => $labels);
+ foreach ($auto_raw as $key => $st) {
+ $st = preg_split("/\015\012|\015|\012/", $st, -1, PREG_SPLIT_NO_EMPTY);
+ foreach ($st as $s) {
+ $v = '';
+ $d = '';
+ $_s = explode('=', $s, 2);
+ if (count($_s) > 1) {
+ $v = trim($_s[0]);
+ $d = trim($_s[1]);
+ } else {
+ $v = trim($_s[0]);
+ }
+ $auto[$key] .= sprintf('{ name: "%s", to: "%s" }, ',
+ Pluf_esc($d),
+ Pluf_esc($v));
+ }
+ $auto[$key] = substr($auto[$key], 0, -2);
+ }
+
+ return $auto;
+ }
}
diff --git a/src/IDF/Views/Source.php b/src/IDF/Views/Source.php
index 38913f0..225d74a 100644
--- a/src/IDF/Views/Source.php
+++ b/src/IDF/Views/Source.php
@@ -132,6 +132,12 @@ class IDF_Views_Source
$request);
}
+ public function repository($request, $match)
+ {
+ $scm = IDF_Scm::get($request->project);
+ return $scm->repository($request, $match);
+ }
+
public $treeBase_precond = array('IDF_Precondition::accessSource',
'IDF_Views_Source_Precondition::scmAvailable',
'IDF_Views_Source_Precondition::revisionValid');
diff --git a/src/IDF/Views/Wiki.php b/src/IDF/Views/Wiki.php
index 972d2c2..8b6d7df 100644
--- a/src/IDF/Views/Wiki.php
+++ b/src/IDF/Views/Wiki.php
@@ -32,22 +32,22 @@ Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
class IDF_Views_Wiki
{
/**
- * View list of issues for a given project.
+ * View list of pages for a given project.
*/
- public $index_precond = array('IDF_Precondition::accessWiki');
- public function index($request, $match, $api=false)
+ public $listPages_precond = array('IDF_Precondition::accessWiki');
+ public function listPages($request, $match, $api=false)
{
$prj = $request->project;
$title = sprintf(__('%s Documentation'), (string) $prj);
// Paginator to paginate the pages
- $pag = new Pluf_Paginator(new IDF_WikiPage());
+ $pag = new Pluf_Paginator(new IDF_Wiki_Page());
$pag->class = 'recent-issues';
$pag->item_extra_props = array('project_m' => $prj,
'shortname' => $prj->shortname,
'current_user' => $request->user);
$pag->summary = __('This table shows the documentation pages.');
- $pag->action = array('IDF_Views_Wiki::index', array($prj->shortname));
- $pag->edit_action = array('IDF_Views_Wiki::view', 'shortname', 'title');
+ $pag->action = array('IDF_Views_Wiki::listPages', array($prj->shortname));
+ $pag->edit_action = array('IDF_Views_Wiki::viewPage', 'shortname', 'title');
$sql = 'project=%s';
$ptags = self::getWikiTags($prj);
$dtag = array_pop($ptags); // The last tag is the deprecated tag.
@@ -67,7 +67,7 @@ class IDF_Views_Wiki
$pag->no_results_text = __('No documentation pages were found.');
$pag->sort_order = array('title', 'ASC');
$pag->setFromRequest($request);
- return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/listPages.html',
array(
'page_title' => $title,
'pages' => $pag,
@@ -77,18 +77,56 @@ class IDF_Views_Wiki
$request);
}
+ /**
+ * View list of resources for a given project.
+ */
+ public $listResources_precond = array('IDF_Precondition::accessWiki',
+ 'Pluf_Precondition::loginRequired');
+ public function listResources($request, $match)
+ {
+ $prj = $request->project;
+ $title = sprintf(__('%s Documentation Resources'), (string) $prj);
+ $pag = new Pluf_Paginator(new IDF_Wiki_Resource());
+ $pag->class = 'recent-issues';
+ $pag->item_extra_props = array('project_m' => $prj,
+ 'shortname' => $prj->shortname,
+ 'current_user' => $request->user);
+ $pag->summary = __('This table shows the resources that can be used on documentation pages.');
+ $pag->action = array('IDF_Views_Wiki::listResources', array($prj->shortname));
+ $pag->edit_action = array('IDF_Views_Wiki::viewResource', 'shortname', 'title');
+ $pag->forced_where = new Pluf_SQL('project=%s', array($prj->id));
+ $pag->extra_classes = array('right', 'a-c', 'left', 'a-c');
+ $list_display = array(
+ 'title' => __('Resource Title'),
+ 'mime_type' => __('MIME type'),
+ 'summary' => __('Description'),
+ array('modif_dtime', 'Pluf_Paginator_DateYMD', __('Updated')),
+ );
+ $pag->configure($list_display, array(), array('title', 'modif_dtime'));
+ $pag->items_per_page = 25;
+ $pag->no_results_text = __('No resources were found.');
+ $pag->sort_order = array('title', 'ASC');
+ $pag->setFromRequest($request);
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/listResources.html',
+ array(
+ 'page_title' => $title,
+ 'resources' => $pag,
+ ),
+ $request);
+ }
+
public $search_precond = array('IDF_Precondition::accessWiki',);
public function search($request, $match)
{
$prj = $request->project;
if (!isset($request->REQUEST['q']) or trim($request->REQUEST['q']) == '') {
- $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::index',
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::listPages',
array($prj->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
$q = $request->REQUEST['q'];
$title = sprintf(__('Documentation Search - %s'), $q);
- $pages = new Pluf_Search_ResultSet(IDF_Search::mySearch($q, $prj, 'IDF_WikiPage'));
+ $pages = new Pluf_Search_ResultSet(IDF_Search::mySearch($q, $prj, 'IDF_Wiki_Page'));
if (count($pages) > 100) {
$pages->results = array_slice($pages->results, 0, 100);
}
@@ -100,7 +138,7 @@ class IDF_Views_Wiki
'current_user' => $request->user);
$pag->summary = __('This table shows the pages found.');
$pag->action = array('IDF_Views_Wiki::search', array($prj->shortname), array('q'=> $q));
- $pag->edit_action = array('IDF_Views_Wiki::view', 'shortname', 'title');
+ $pag->edit_action = array('IDF_Views_Wiki::viewPage', 'shortname', 'title');
$pag->extra_classes = array('right', '', 'a-c');
$list_display = array(
'title' => __('Page Title'),
@@ -122,8 +160,8 @@ class IDF_Views_Wiki
/**
* View list of pages with a given label.
*/
- public $listLabel_precond = array('IDF_Precondition::accessWiki');
- public function listLabel($request, $match)
+ public $listPagesWithLabel_precond = array('IDF_Precondition::accessWiki');
+ public function listPagesWithLabel($request, $match)
{
$prj = $request->project;
$tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $match[2]);
@@ -133,15 +171,15 @@ class IDF_Views_Wiki
// Paginator to paginate the pages
$ptags = self::getWikiTags($prj);
$dtag = array_pop($ptags); // The last tag is the deprecated tag.
- $pag = new Pluf_Paginator(new IDF_WikiPage());
+ $pag = new Pluf_Paginator(new IDF_Wiki_Page());
$pag->model_view = 'join_tags';
$pag->class = 'recent-issues';
$pag->item_extra_props = array('project_m' => $prj,
'shortname' => $prj->shortname);
$pag->summary = sprintf(__('This table shows the documentation pages with label %s.'), (string) $tag);
$pag->forced_where = new Pluf_SQL('project=%s AND idf_tag_id=%s', array($prj->id, $tag->id));
- $pag->action = array('IDF_Views_Wiki::listLabel', array($prj->shortname, $tag->id));
- $pag->edit_action = array('IDF_Views_Wiki::view', 'shortname', 'title');
+ $pag->action = array('IDF_Views_Wiki::listPagesWithLabel', array($prj->shortname, $tag->id));
+ $pag->edit_action = array('IDF_Views_Wiki::viewPage', 'shortname', 'title');
$pag->extra_classes = array('right', '', 'a-c');
$list_display = array(
'title' => __('Page Title'),
@@ -152,7 +190,7 @@ class IDF_Views_Wiki
$pag->items_per_page = 25;
$pag->no_results_text = __('No documentation pages were found.');
$pag->setFromRequest($request);
- return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/listPages.html',
array(
'page_title' => $title,
'label' => $tag,
@@ -165,24 +203,25 @@ class IDF_Views_Wiki
/**
* Create a new documentation page.
*/
- public $create_precond = array('IDF_Precondition::accessWiki',
- 'Pluf_Precondition::loginRequired');
- public function create($request, $match)
+ public $createPage_precond = array('IDF_Precondition::accessWiki',
+ 'Pluf_Precondition::loginRequired');
+ public function createPage($request, $match)
{
$prj = $request->project;
$title = __('New Page');
$preview = false;
if ($request->method == 'POST') {
- $form = new IDF_Form_WikiCreate($request->POST,
+ $form = new IDF_Form_WikiPageCreate($request->POST,
array('project' => $prj,
'user' => $request->user
));
if ($form->isValid() and !isset($request->POST['preview'])) {
$page = $form->save();
- $urlpage = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
+ $urlpage = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewPage',
array($prj->shortname, $page->title));
- $request->user->setMessage(sprintf(__('The page %2$s has been created.'), $urlpage, Pluf_esc($page->title)));
- $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::index',
+ $request->user->setMessage(sprintf(__('The page %2$s has been created.'),
+ $urlpage, Pluf_esc($page->title)));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::listPages',
array($prj->shortname));
return new Pluf_HTTP_Response_Redirect($url);
} elseif (isset($request->POST['preview'])) {
@@ -191,12 +230,12 @@ class IDF_Views_Wiki
} else {
$pagename = (isset($request->GET['name'])) ?
$request->GET['name'] : '';
- $form = new IDF_Form_WikiCreate(null,
+ $form = new IDF_Form_WikiPageCreate(null,
array('name' => $pagename,
'project' => $prj,
'user' => $request->user));
}
- return Pluf_Shortcuts_RenderToResponse('idf/wiki/create.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/createPage.html',
array(
'auto_labels' => self::autoCompleteArrays($prj),
'page_title' => $title,
@@ -206,27 +245,65 @@ class IDF_Views_Wiki
$request);
}
+ /**
+ * Create a new resource.
+ */
+ public $createResource_precond = array('IDF_Precondition::accessWiki',
+ 'Pluf_Precondition::loginRequired');
+ public function createResource($request, $match)
+ {
+ $prj = $request->project;
+ $title = __('New Resource');
+ $preview = false;
+ if ($request->method == 'POST') {
+ $form = new IDF_Form_WikiResourceCreate(array_merge($request->POST, $request->FILES),
+ array('project' => $prj, 'user' => $request->user));
+ if ($form->isValid()) {
+ $resource = $form->save();
+ $urlresource = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource',
+ array($prj->shortname, $resource->title));
+ $request->user->setMessage(sprintf(__('The resource %2$s has been created.'), $urlresource, Pluf_esc($resource->title)));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::listResources',
+ array($prj->shortname));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+ } else {
+ $resourcename = (isset($request->GET['name'])) ?
+ $request->GET['name'] : '';
+ $form = new IDF_Form_WikiResourceCreate(null,
+ array('name' => $resourcename,
+ 'project' => $prj, 'user' => $request->user));
+ }
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/createResource.html',
+ array(
+ 'page_title' => $title,
+ 'form' => $form,
+ ),
+ $request);
+ }
+
/**
* View a documentation page.
*/
- public $view_precond = array('IDF_Precondition::accessWiki');
- public function view($request, $match)
+ public $viewPage_precond = array('IDF_Precondition::accessWiki');
+ public function viewPage($request, $match)
{
$prj = $request->project;
// Find the page
- $sql = new Pluf_SQL('project=%s AND title=%s',
+ $sql = new Pluf_SQL('project=%s AND title=%s',
array($prj->id, $match[2]));
- $pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
+ $pages = Pluf::factory('IDF_Wiki_Page')->getList(array('filter'=>$sql->gen()));
if ($pages->count() != 1) {
return new Pluf_HTTP_Response_NotFound($request);
}
$page = $pages[0];
- $oldrev = false;
+ $revision = $page->get_current_revision();
+
// We grab the old revision if requested.
if (isset($request->GET['rev']) and preg_match('/^[0-9]+$/', $request->GET['rev'])) {
- $oldrev = Pluf_Shortcuts_GetObjectOr404('IDF_WikiRevision',
+ $revision = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_PageRevision',
$request->GET['rev']);
- if ($oldrev->wikipage != $page->id or $oldrev->is_head == true) {
+ if ($revision->wikipage != $page->id) {
return new Pluf_HTTP_Response_NotFound($request);
}
}
@@ -235,15 +312,13 @@ class IDF_Views_Wiki
$tags = $page->get_tags_list();
$dep = Pluf_Model_InArray($dtag, $tags);
$title = $page->title;
- $revision = $page->get_current_revision();
$false = Pluf_DB_BooleanToDb(false, $page->getDbConnection());
$revs = $page->get_revisions_list(array('order' => 'creation_dtime DESC',
'filter' => 'is_head='.$false));
- return Pluf_Shortcuts_RenderToResponse('idf/wiki/view.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/viewPage.html',
array(
'page_title' => $title,
'page' => $page,
- 'oldrev' => $oldrev,
'rev' => $revision,
'revs' => $revs,
'tags' => $tags,
@@ -253,14 +328,77 @@ class IDF_Views_Wiki
}
/**
- * Remove a revision of a page.
+ * View a documentation resource.
*/
- public $deleteRev_precond = array('IDF_Precondition::accessWiki',
- 'IDF_Precondition::projectMemberOrOwner');
- public function deleteRev($request, $match)
+ public $viewResource_precond = array('IDF_Precondition::accessWiki');
+ public function viewResource($request, $match)
{
$prj = $request->project;
- $oldrev = Pluf_Shortcuts_GetObjectOr404('IDF_WikiRevision', $match[2]);
+ $sql = new Pluf_SQL('project=%s AND title=%s',
+ array($prj->id, $match[2]));
+ $resources = Pluf::factory('IDF_Wiki_Resource')->getList(array('filter'=>$sql->gen()));
+ if ($resources->count() != 1) {
+ return new Pluf_HTTP_Response_NotFound($request);
+ }
+ $resource = $resources[0];
+ $revision = $resource->get_current_revision();
+
+ // grab the old revision if requested.
+ if (isset($request->GET['rev']) and preg_match('/^[0-9]+$/', $request->GET['rev'])) {
+ $revision = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_ResourceRevision',
+ $request->GET['rev']);
+ if ($revision->wikiresource != $resource->id) {
+ return new Pluf_HTTP_Response_NotFound($request);
+ }
+ }
+ $pagerevs = $revision->getPageRevisions();
+ $title = $resource->title;
+ $false = Pluf_DB_BooleanToDb(false, $resource->getDbConnection());
+ $revs = $resource->get_revisions_list(array('order' => 'creation_dtime DESC',
+ 'filter' => 'is_head='.$false));
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/viewResource.html',
+ array(
+ 'page_title' => $title,
+ 'resource' => $resource,
+ 'rev' => $revision,
+ 'revs' => $revs,
+ 'pagerevs' => $pagerevs,
+ ),
+ $request);
+ }
+
+
+ /**
+ * Returns a bytestream to the given raw resource revision
+ */
+ public $rawResource_precond = array('IDF_Precondition::accessWiki');
+ public function rawResource($request, $match)
+ {
+ $prj = $request->project;
+ $rev = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_ResourceRevision',
+ $match[2]);
+ $res = $rev->get_wikiresource();
+ if ($res->get_project()->id != $prj->id) {
+ return new Pluf_HTTP_Response_NotFound($request);
+ }
+
+ $response = new Pluf_HTTP_Response_File($rev->getFilePath(), $res->mime_type);
+ if (isset($request->GET['attachment']) && $request->GET['attachment']) {
+ $response->headers['Content-Disposition'] =
+ 'attachment; filename="'.$res->title.'.'.$rev->fileext.'"';
+ }
+ return $response;
+ }
+
+ /**
+ * Remove a revision of a page.
+ */
+ public $deletePageRev_precond = array('IDF_Precondition::accessWiki',
+ 'IDF_Precondition::projectMemberOrOwner');
+ public function deletePageRev($request, $match)
+ {
+ $prj = $request->project;
+ $oldrev = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_PageRevision', $match[2]);
$page = $oldrev->get_wikipage();
$prj->inOr404($page);
if ($oldrev->is_head == true) {
@@ -269,7 +407,7 @@ class IDF_Views_Wiki
if ($request->method == 'POST') {
$oldrev->delete();
$request->user->setMessage(__('The old revision has been deleted.'));
- $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewPage',
array($prj->shortname, $page->title));
return new Pluf_HTTP_Response_Redirect($url);
}
@@ -279,7 +417,7 @@ class IDF_Views_Wiki
$false = Pluf_DB_BooleanToDb(false, $page->getDbConnection());
$revs = $page->get_revisions_list(array('order' => 'creation_dtime DESC',
'filter' => 'is_head='.$false));
- return Pluf_Shortcuts_RenderToResponse('idf/wiki/delete.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/deletePageRev.html',
array(
'page_title' => $title,
'page' => $page,
@@ -292,17 +430,53 @@ class IDF_Views_Wiki
}
/**
- * View a documentation page.
+ * Remove a revision of a resource.
*/
- public $update_precond = array('IDF_Precondition::accessWiki',
- 'Pluf_Precondition::loginRequired');
- public function update($request, $match)
+ public $deleteResourceRev_precond = array('IDF_Precondition::accessWiki',
+ 'IDF_Precondition::projectMemberOrOwner');
+ public function deleteResourceRev($request, $match)
+ {
+ $prj = $request->project;
+ $oldrev = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_ResourceRevision', $match[2]);
+ $resource = $oldrev->get_wikiresource();
+ $prj->inOr404($resource);
+ if ($oldrev->is_head == true) {
+ return new Pluf_HTTP_Response_NotFound($request);
+ }
+ if ($request->method == 'POST') {
+ $oldrev->delete();
+ $request->user->setMessage(__('The old revision has been deleted.'));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource',
+ array($prj->shortname, $resource->title));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+
+ $title = sprintf(__('Delete Old Revision of %s'), $resource->title);
+ $false = Pluf_DB_BooleanToDb(false, $resource->getDbConnection());
+ $revs = $resource->get_revisions_list(array('order' => 'creation_dtime DESC',
+ 'filter' => 'is_head='.$false));
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/deleteResourceRev.html',
+ array(
+ 'page_title' => $title,
+ 'resource' => $resource,
+ 'oldrev' => $oldrev,
+ 'revs' => $revs,
+ ),
+ $request);
+ }
+
+ /**
+ * Update a documentation page.
+ */
+ public $updatePage_precond = array('IDF_Precondition::accessWiki',
+ 'Pluf_Precondition::loginRequired');
+ public function updatePage($request, $match)
{
$prj = $request->project;
// Find the page
- $sql = new Pluf_SQL('project=%s AND title=%s',
+ $sql = new Pluf_SQL('project=%s AND title=%s',
array($prj->id, $match[2]));
- $pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
+ $pages = Pluf::factory('IDF_Wiki_Page')->getList(array('filter'=>$sql->gen()));
if ($pages->count() != 1) {
return new Pluf_HTTP_Response_NotFound($request);
}
@@ -314,23 +488,24 @@ class IDF_Views_Wiki
'user' => $request->user,
'page' => $page);
if ($request->method == 'POST') {
- $form = new IDF_Form_WikiUpdate($request->POST, $params);
+ $form = new IDF_Form_WikiPageUpdate($request->POST, $params);
if ($form->isValid() and !isset($request->POST['preview'])) {
$page = $form->save();
- $urlpage = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
+ $urlpage = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewPage',
array($prj->shortname, $page->title));
- $request->user->setMessage(sprintf(__('The page %2$s has been updated.'), $urlpage, Pluf_esc($page->title)));
- $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::index',
+ $request->user->setMessage(sprintf(__('The page %2$s has been updated.'),
+ $urlpage, Pluf_esc($page->title)));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::listPages',
array($prj->shortname));
return new Pluf_HTTP_Response_Redirect($url);
} elseif (isset($request->POST['preview'])) {
$preview = $request->POST['content'];
}
} else {
-
- $form = new IDF_Form_WikiUpdate(null, $params);
+
+ $form = new IDF_Form_WikiPageUpdate(null, $params);
}
- return Pluf_Shortcuts_RenderToResponse('idf/wiki/update.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/updatePage.html',
array(
'auto_labels' => self::autoCompleteArrays($prj),
'page_title' => $title,
@@ -343,34 +518,82 @@ class IDF_Views_Wiki
}
/**
- * Delete a Wiki page.
+ * Update a documentation resource.
*/
- public $delete_precond = array('IDF_Precondition::accessWiki',
- 'IDF_Precondition::projectMemberOrOwner');
- public function delete($request, $match)
+ public $updateResource_precond = array('IDF_Precondition::accessWiki',
+ 'Pluf_Precondition::loginRequired');
+ public function updateResource($request, $match)
{
$prj = $request->project;
- $page = Pluf_Shortcuts_GetObjectOr404('IDF_WikiPage', $match[2]);
- $prj->inOr404($page);
- $params = array('page' => $page);
+ // Find the page
+ $sql = new Pluf_SQL('project=%s AND title=%s',
+ array($prj->id, $match[2]));
+ $resources = Pluf::factory('IDF_Wiki_Resource')->getList(array('filter'=>$sql->gen()));
+ if ($resources->count() != 1) {
+ return new Pluf_HTTP_Response_NotFound($request);
+ }
+ $resource = $resources[0];
+ $title = sprintf(__('Update %s'), $resource->title);
+ $revision = $resource->get_current_revision();
+ $params = array('project' => $prj,
+ 'user' => $request->user,
+ 'resource' => $resource);
if ($request->method == 'POST') {
- $form = new IDF_Form_WikiDelete($request->POST, $params);
+ $form = new IDF_Form_WikiResourceUpdate(array_merge($request->POST, $request->FILES),
+ $params);
if ($form->isValid()) {
- $form->save();
- $request->user->setMessage(__('The documentation page has been deleted.'));
- $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::index',
+ $page = $form->save();
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource',
+ array($prj->shortname, $resource->title));
+ $request->user->setMessage(sprintf(__('The resource %2$s has been updated.'),
+ $url, Pluf_esc($resource->title)));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::listResources',
array($prj->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
} else {
- $form = new IDF_Form_WikiDelete(null, $params);
+ $form = new IDF_Form_WikiResourceUpdate(null, $params);
+ }
+
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/updateResource.html',
+ array(
+ 'page_title' => $title,
+ 'resource' => $resource,
+ 'rev' => $revision,
+ 'form' => $form,
+ ),
+ $request);
+ }
+
+ /**
+ * Delete a Wiki page.
+ */
+ public $deletePage_precond = array('IDF_Precondition::accessWiki',
+ 'IDF_Precondition::projectMemberOrOwner');
+ public function deletePage($request, $match)
+ {
+ $prj = $request->project;
+ $page = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_Page', $match[2]);
+ $prj->inOr404($page);
+ $params = array('page' => $page);
+ if ($request->method == 'POST') {
+ $form = new IDF_Form_WikiPageDelete($request->POST, $params);
+ if ($form->isValid()) {
+ $form->save();
+ $request->user->setMessage(__('The documentation page has been deleted.'));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::listPages',
+ array($prj->shortname));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+ } else {
+ $form = new IDF_Form_WikiPageDelete(null, $params);
}
$title = sprintf(__('Delete Page %s'), $page->title);
$revision = $page->get_current_revision();
$false = Pluf_DB_BooleanToDb(false, $page->getDbConnection());
$revs = $page->get_revisions_list(array('order' => 'creation_dtime DESC',
'filter' => 'is_head='.$false));
- return Pluf_Shortcuts_RenderToResponse('idf/wiki/deletepage.html',
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/deletePage.html',
array(
'page_title' => $title,
'page' => $page,
@@ -382,6 +605,45 @@ class IDF_Views_Wiki
$request);
}
+ /**
+ * Delete a Wiki resource.
+ */
+ public $deleteResource_precond = array('IDF_Precondition::accessWiki',
+ 'IDF_Precondition::projectMemberOrOwner');
+ public function deleteResource($request, $match)
+ {
+ $prj = $request->project;
+ $resource = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_Resource', $match[2]);
+ $prj->inOr404($resource);
+ $params = array('resource' => $resource);
+ if ($request->method == 'POST') {
+ $form = new IDF_Form_WikiResourceDelete($request->POST, $params);
+ if ($form->isValid()) {
+ $form->save();
+ $request->user->setMessage(__('The documentation resource has been deleted.'));
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::listResources',
+ array($prj->shortname));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+ } else {
+ $form = new IDF_Form_WikiResourceDelete(null, $params);
+ }
+ $title = sprintf(__('Delete Resource %s'), $resource->title);
+ $revision = $resource->get_current_revision();
+ $false = Pluf_DB_BooleanToDb(false, $resource->getDbConnection());
+ $revs = $resource->get_revisions_list(array('order' => 'creation_dtime DESC',
+ 'filter' => 'is_head='.$false));
+ return Pluf_Shortcuts_RenderToResponse('idf/wiki/deleteResource.html',
+ array(
+ 'page_title' => $title,
+ 'resource' => $resource,
+ 'form' => $form,
+ 'rev' => $revision,
+ 'revs' => $revs,
+ ),
+ $request);
+ }
+
/**
* Get the wiki tags.
*
@@ -411,7 +673,7 @@ class IDF_Views_Wiki
$sql = new Pluf_SQL('project=%s AND idf_tag_id=%s', array($project->id,
$dtag->id));
$ids = array();
- foreach (Pluf::factory('IDF_WikiPage')->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'))
+ foreach (Pluf::factory('IDF_Wiki_Page')->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'))
as $file) {
$ids[] = (int) $file->id;
}
@@ -425,7 +687,7 @@ class IDF_Views_Wiki
{
$conf = new IDF_Conf();
$conf->setProject($project);
- $st = preg_split("/\015\012|\015|\012/",
+ $st = preg_split("/\015\012|\015|\012/",
$conf->getVal('labels_wiki_predefined', IDF_Form_WikiConf::init_predefined), -1, PREG_SPLIT_NO_EMPTY);
$auto = '';
foreach ($st as $s) {
diff --git a/src/IDF/Webhook.php b/src/IDF/Webhook.php
index 34a5cda..9d33d09 100644
--- a/src/IDF/Webhook.php
+++ b/src/IDF/Webhook.php
@@ -31,22 +31,28 @@
class IDF_Webhook
{
/**
- * Perform the POST request given the webhook payload.
+ * Perform the request given the webhook payload.
*
* @param array Payload
* @return bool Success or error
*/
- public static function postNotification($payload)
+ public static function processNotification($payload)
{
$data = json_encode($payload['to_send']);
+ $sign_header = 'Web-Hook-Hmac';
+ // use the old signature header if we're asked for
+ if (Pluf::f('webhook_processing', '') === 'compat') {
+ $sign_header = 'Post-Commit-Hook-Hmac';
+ }
$sign = hash_hmac('md5', $data, $payload['authkey']);
$params = array('http' => array(
- 'method' => 'POST',
+ // fall-back to POST for old queue items
+ 'method' => empty($payload['method']) ? 'POST' : $payload['method'],
'content' => $data,
'user_agent' => 'Indefero Hook Sender (http://www.indefero.net)',
- 'max_redirects' => 0,
+ 'max_redirects' => 0,
'timeout' => 15,
- 'header'=> 'Post-Commit-Hook-Hmac: '.$sign."\r\n"
+ 'header'=> $sign_header.': '.$sign."\r\n"
.'Content-Type: application/json'."\r\n",
)
);
@@ -61,7 +67,7 @@ class IDF_Webhook
if (!isset($meta['wrapper_data'][0]) or $meta['timed_out']) {
return false;
}
- if (0 === strpos($meta['wrapper_data'][0], 'HTTP/1.1 2') or
+ if (0 === strpos($meta['wrapper_data'][0], 'HTTP/1.1 2') or
0 === strpos($meta['wrapper_data'][0], 'HTTP/1.1 3')) {
return true;
}
@@ -76,11 +82,11 @@ class IDF_Webhook
public static function process($sender, &$params)
{
$item = $params['item'];
- if ($item->type != 'new_commit') {
+ if (!in_array($item->type, array('new_commit', 'upload'))) {
// We do nothing.
return;
}
- if (isset($params['res']['IDF_Webhook::process']) and
+ if (isset($params['res']['IDF_Webhook::process']) and
$params['res']['IDF_Webhook::process'] == true) {
// Already processed.
return;
@@ -90,7 +96,7 @@ class IDF_Webhook
return;
}
// We have either to retry or to push for the first time.
- $res = self::postNotification($item->payload);
+ $res = self::processNotification($item->payload);
if ($res) {
$params['res']['IDF_Webhook::process'] = true;
} elseif ($item->trials >= 9) {
diff --git a/src/IDF/WikiPage.php b/src/IDF/Wiki/Page.php
similarity index 91%
rename from src/IDF/WikiPage.php
rename to src/IDF/Wiki/Page.php
index de1a318..0c4a35c 100644
--- a/src/IDF/WikiPage.php
+++ b/src/IDF/Wiki/Page.php
@@ -28,10 +28,10 @@ Pluf::loadFunction('Pluf_Template_dateAgo');
* Base definition of a wiki page.
*
* A wiki page can have tags and be starred by the users. The real
- * content of the page is stored in the IDF_WikiRevision
+ * content of the page is stored in the IDF_Wiki_PageRevision
* object. Several revisions are associated to a given page.
*/
-class IDF_WikiPage extends Pluf_Model
+class IDF_Wiki_Page extends Pluf_Model
{
public $_model = __CLASS__;
@@ -44,9 +44,9 @@ class IDF_WikiPage extends Pluf_Model
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
- 'blank' => true,
+ 'blank' => true,
),
- 'project' =>
+ 'project' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Project',
@@ -70,7 +70,7 @@ class IDF_WikiPage extends Pluf_Model
'verbose' => __('summary'),
'help_text' => __('A one line description of the page content.'),
),
- 'submitter' =>
+ 'submitter' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'Pluf_User',
@@ -78,7 +78,7 @@ class IDF_WikiPage extends Pluf_Model
'verbose' => __('submitter'),
'relate_name' => 'submitted_wikipages',
),
- 'interested' =>
+ 'interested' =>
array(
'type' => 'Pluf_DB_Field_Manytomany',
'model' => 'Pluf_User',
@@ -88,7 +88,7 @@ class IDF_WikiPage extends Pluf_Model
),
'tags' =>
array(
- 'type' => 'Pluf_DB_Field_Manytomany',
+ 'type' => 'Pluf_DB_Field_Manytomany',
'blank' => true,
'model' => 'IDF_Tag',
'verbose' => __('labels'),
@@ -106,19 +106,19 @@ class IDF_WikiPage extends Pluf_Model
'verbose' => __('modification date'),
),
);
- $this->_a['idx'] = array(
+ $this->_a['idx'] = array(
'modif_dtime_idx' =>
array(
'col' => 'modif_dtime',
'type' => 'normal',
),
);
- $table = $this->_con->pfx.'idf_tag_idf_wikipage_assoc';
+ $table = $this->_con->pfx.'idf_tag_idf_wiki_page_assoc';
$this->_a['views'] = array(
- 'join_tags' =>
+ 'join_tags' =>
array(
'join' => 'LEFT JOIN '.$table
- .' ON idf_wikipage_id=id',
+ .' ON idf_wiki_page_id=id',
),
);
}
@@ -144,7 +144,7 @@ class IDF_WikiPage extends Pluf_Model
IDF_Search::remove($this);
}
- function get_current_revision()
+ function get_current_revision()
{
$true = Pluf_DB_BooleanToDb(true, $this->getDbConnection());
$rev = $this->get_revisions_list(array('filter' => 'is_head='.$true,
@@ -167,7 +167,7 @@ class IDF_WikiPage extends Pluf_Model
// that the page as a given revision in the database when
// doing the indexing.
if ($create) {
- IDF_Timeline::insert($this, $this->get_project(),
+ IDF_Timeline::insert($this, $this->get_project(),
$this->get_submitter());
}
}
@@ -180,12 +180,12 @@ class IDF_WikiPage extends Pluf_Model
* as such create links to other items etc. You can consider that
* if displayed, you can create a link to it.
*
- * @param Pluf_HTTP_Request
+ * @param Pluf_HTTP_Request
* @return Pluf_Template_SafeString
*/
public function timelineFragment($request)
{
- $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewPage',
array($request->project->shortname,
$this->title));
$out = '
'.
@@ -195,14 +195,14 @@ class IDF_WikiPage extends Pluf_Model
$user = $stag->start($this->get_submitter(), $request, '', false);
$out .= sprintf(__('%2$s, %3$s'), $url, Pluf_esc($this->title), Pluf_esc($this->summary)).' ';
$out .= "\n".' ';
+
- '.
Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
' ';
@@ -193,18 +222,12 @@ class IDF_WikiRevision extends Pluf_Model
public function feedFragment($request)
{
$page = $this->get_wikipage();
- if (!$this->is_head) {
- $url = Pluf::f('url_base')
- .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
- array($request->project->shortname,
- $page->title),
- array('rev' => $this->id));
- } else {
- $url = Pluf::f('url_base')
- .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
- array($request->project->shortname,
- $page->title));
- }
+ $url = Pluf::f('url_base')
+ .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewPage',
+ array($request->project->shortname,
+ $page->title),
+ array('rev' => $this->id));
+
$title = sprintf(__('%1$s: Documentation page %2$s updated - %3$s'),
$request->project->name,
$page->title, $page->summary);
@@ -218,14 +241,14 @@ class IDF_WikiRevision extends Pluf_Model
'create' => false,
'date' => $date)
);
- $tmpl = new Pluf_Template('idf/wiki/feedfragment.xml');
+ $tmpl = new Pluf_Template('idf/wiki/feedfragment-page.xml');
return $tmpl->render($context);
}
/**
- * Notification of change of a WikiPage.
+ * Notification of change of a Wiki Page.
*
* The content of a WikiPage is in the IDF_WikiRevision object,
* this is why we send the notificatin from there. This means that
@@ -243,42 +266,49 @@ class IDF_WikiRevision extends Pluf_Model
*/
public function notify($conf, $create=true)
{
- if ('' == $conf->getVal('wiki_notification_email', '')) {
- return;
- }
+ $wikipage = $this->get_wikipage();
+ $project = $wikipage->get_project();
$current_locale = Pluf_Translation::getLocale();
- $langs = Pluf::f('languages', array('en'));
- Pluf_Translation::loadSetLocale($langs[0]);
- $context = new Pluf_Template_Context(
- array(
- 'page' => $this->get_wikipage(),
- 'rev' => $this,
- 'project' => $this->get_wikipage()->get_project(),
- 'url_base' => Pluf::f('url_base'),
- )
- );
- if ($create) {
- $template = 'idf/wiki/wiki-created-email.txt';
- $title = sprintf(__('New Documentation Page %1$s - %2$s (%3$s)'),
- $this->get_wikipage()->title,
- $this->get_wikipage()->summary,
- $this->get_wikipage()->get_project()->shortname);
- } else {
- $template = 'idf/wiki/wiki-updated-email.txt';
- $title = sprintf(__('Documentation Page Changed %1$s - %2$s (%3$s)'),
- $this->get_wikipage()->title,
- $this->get_wikipage()->summary,
- $this->get_wikipage()->get_project()->shortname);
- }
- $tmpl = new Pluf_Template($template);
- $text_email = $tmpl->render($context);
- $addresses = explode(',', $conf->getVal('wiki_notification_email'));
- foreach ($addresses as $address) {
- $email = new Pluf_Mail(Pluf::f('from_email'),
+ $from_email = Pluf::f('from_email');
+ $messageId = '<'.md5('wiki'.$wikipage->id.md5(Pluf::f('secret_key'))).'@'.Pluf::f('mail_host', 'localhost').'>';
+ $recipients = $project->getNotificationRecipientsForTab('wiki');
+
+ foreach ($recipients as $address => $language) {
+
+ if ($this->get_submitter()->email === $address) {
+ continue;
+ }
+
+ Pluf_Translation::loadSetLocale($language);
+
+ $context = new Pluf_Template_Context(array(
+ 'page' => $wikipage,
+ 'rev' => $this,
+ 'project' => $project,
+ 'url_base' => Pluf::f('url_base'),
+ ));
+
+ $tplfile = 'idf/wiki/wiki-created-email.txt';
+ $subject = __('New Documentation Page %1$s - %2$s (%3$s)');
+ $headers = array('Message-ID' => $messageId);
+ if (!$create) {
+ $tplfile = 'idf/wiki/wiki-updated-email.txt';
+ $subject = __('Documentation Page Changed %1$s - %2$s (%3$s)');
+ $headers = array('References' => $messageId);
+ }
+
+ $tmpl = new Pluf_Template($tplfile);
+ $text_email = $tmpl->render($context);
+
+ $email = new Pluf_Mail($from_email,
$address,
- $title);
+ sprintf($subject,
+ $wikipage->title,
+ $wikipage->summary,
+ $project->shortname));
$email->addTextMessage($text_email);
+ $email->addHeaders($headers);
$email->sendMail();
}
diff --git a/src/IDF/Wiki/Resource.php b/src/IDF/Wiki/Resource.php
new file mode 100644
index 0000000..487cf1a
--- /dev/null
+++ b/src/IDF/Wiki/Resource.php
@@ -0,0 +1,204 @@
+_a['table'] = 'idf_wikiresources';
+ $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' => 'wikipages',
+ ),
+ 'title' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Varchar',
+ 'blank' => false,
+ 'size' => 250,
+ 'verbose' => __('title'),
+ 'help_text' => __('The title of the resource must only contain letters, digits, dots or the dash character. For example: my-resource.png.'),
+ ),
+ 'mime_type' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Varchar',
+ 'blank' => false,
+ 'size' => 100,
+ 'verbose' => __('MIME media type'),
+ 'help_text' => __('The MIME media type of the resource.'),
+ ),
+ 'summary' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Varchar',
+ 'blank' => false,
+ 'size' => 250,
+ 'verbose' => __('summary'),
+ 'help_text' => __('A one line description of the resource.'),
+ ),
+ 'submitter' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Foreignkey',
+ 'model' => 'Pluf_User',
+ 'blank' => false,
+ 'verbose' => __('submitter'),
+ 'relate_name' => 'submitted_wikipages',
+ ),
+ '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',
+ ),
+ );
+ }
+
+ function __toString()
+ {
+ return $this->title.' - '.$this->summary;
+ }
+
+ /**
+ * We drop the information from the timeline.
+ */
+ function preDelete()
+ {
+ IDF_Timeline::remove($this);
+ IDF_Search::remove($this);
+ }
+
+ function get_current_revision()
+ {
+ $true = Pluf_DB_BooleanToDb(true, $this->getDbConnection());
+ $rev = $this->get_revisions_list(array('filter' => 'is_head='.$true,
+ 'nb' => 1));
+ return ($rev->count() == 1) ? $rev[0] : null;
+ }
+
+ function preSave($create=false)
+ {
+ if ($this->id == '') {
+ $this->creation_dtime = gmdate('Y-m-d H:i:s');
+ }
+ $this->modif_dtime = gmdate('Y-m-d H:i:s');
+ }
+
+ function postSave($create=false)
+ {
+ // Note: No indexing is performed here. The indexing is
+ // triggered in the postSave step of the revision to ensure
+ // that the page as a given revision in the database when
+ // doing the indexing.
+ if ($create) {
+ IDF_Timeline::insert($this, $this->get_project(),
+ $this->get_submitter());
+ }
+ }
+
+ /**
+ * Returns an HTML fragment used to display this resource in the
+ * timeline.
+ *
+ * The request object is given to be able to check the rights and
+ * as such create links to other items etc. You can consider that
+ * if displayed, you can create a link to it.
+ *
+ * @param Pluf_HTTP_Request
+ * @return Pluf_Template_SafeString
+ */
+ public function timelineFragment($request)
+ {
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource',
+ array($request->project->shortname,
+ $this->title));
+ $out = ' '.
+ Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
+ ' ';
+ $stag = new IDF_Template_ShowUser();
+ $user = $stag->start($this->get_submitter(), $request, '', false);
+ $out .= sprintf(__('%2$s, %3$s'), $url, Pluf_esc($this->title), Pluf_esc($this->summary)).' ';
+ $out .= "\n".' ';
+ return Pluf_Template::markSafe($out);
+ }
+
+ public function feedFragment($request)
+ {
+ $url = Pluf::f('url_base')
+ .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource',
+ array($request->project->shortname,
+ $this->title));
+ $title = sprintf(__('%1$s: Documentation resource %2$s added - %3$s'),
+ $request->project->name,
+ $this->title, $this->summary);
+ $date = Pluf_Date::gmDateToGmString($this->creation_dtime);
+ $context = new Pluf_Template_Context_Request(
+ $request,
+ array('url' => $url,
+ 'title' => $title,
+ 'resource' => $this,
+ 'rev' => $this->get_current_revision(),
+ 'create' => true,
+ 'date' => $date)
+ );
+ $tmpl = new Pluf_Template('idf/wiki/feedfragment-resource.xml');
+ return $tmpl->render($context);
+ }
+}
diff --git a/src/IDF/Wiki/ResourceRevision.php b/src/IDF/Wiki/ResourceRevision.php
new file mode 100644
index 0000000..ee1a3ea
--- /dev/null
+++ b/src/IDF/Wiki/ResourceRevision.php
@@ -0,0 +1,340 @@
+_a['table'] = 'idf_wikiresourcerevs';
+ $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,
+ ),
+ 'wikiresource' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Foreignkey',
+ 'model' => 'IDF_Wiki_Resource',
+ 'blank' => false,
+ 'verbose' => __('resource'),
+ 'relate_name' => 'revisions',
+ ),
+ 'is_head' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Boolean',
+ 'blank' => false,
+ 'default' => false,
+ 'help_text' => 'If this revision is the latest, we mark it as being the head revision.',
+ 'index' => true,
+ ),
+ 'summary' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Varchar',
+ 'blank' => false,
+ 'size' => 250,
+ 'verbose' => __('summary'),
+ 'help_text' => __('A one line description of the changes.'),
+ ),
+ 'filesize' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Integer',
+ 'blank' => false,
+ 'default' => 0,
+ 'verbose' => __('file size in bytes'),
+ ),
+ 'fileext' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Varchar',
+ 'blank' => false,
+ 'size' => 10,
+ 'verbose' => __('File extension'),
+ 'help_text' => __('The file extension of the uploaded resource.'),
+ ),
+ 'submitter' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Foreignkey',
+ 'model' => 'Pluf_User',
+ 'blank' => false,
+ 'verbose' => __('submitter'),
+ 'relate_name' => 'submitted_downloads',
+ ),
+ 'pageusage' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Manytomany',
+ 'model' => 'IDF_Wiki_PageRevision',
+ 'blank' => true,
+ 'verbose' => __('page usage'),
+ 'help_text' => 'Records on which pages this resource revision is used.',
+ ),
+ 'creation_dtime' =>
+ array(
+ 'type' => 'Pluf_DB_Field_Datetime',
+ 'blank' => true,
+ 'verbose' => __('creation date'),
+ ),
+ );
+ $table = $this->_con->pfx.'idf_wiki_pagerevision_idf_wiki_resourcerevision_assoc';
+ $this->_a['views'] = array(
+ 'join_pagerevision' =>
+ array(
+ 'join' => 'LEFT JOIN '.$table
+ .' ON idf_wiki_resourcerevision_id=id',
+ ),
+ );
+ }
+
+ function __toString()
+ {
+ return sprintf(__('id %d: %s'), $this->id, $this->summary);
+ }
+
+ function _toIndex()
+ {
+ return '';
+ }
+
+ function preDelete()
+ {
+ // if we kill off a head revision, ensure that we either mark a previous revision as head
+ if ($this->is_head) {
+ $sql = new Pluf_SQL('wikiresource=%s and id!=%s', array($this->wikiresource, $this->id));
+ $revs = Pluf::factory('IDF_Wiki_ResourceRevision')->getList(array('filter'=>$sql->gen(), 'order'=>'id DESC'));
+ if ($revs->count() > 0) {
+ $previous = $revs[0];
+ $previous->is_head = true;
+ $previous->update();
+ }
+ }
+
+ @unlink($this->getFilePath());
+ IDF_Timeline::remove($this);
+ }
+
+ function preSave($create=false)
+ {
+ if ($this->id == '') {
+ $this->creation_dtime = gmdate('Y-m-d H:i:s');
+ $this->is_head = true;
+ }
+ }
+
+ function postSave($create=false)
+ {
+ $resource = $this->get_wikiresource();
+
+ if ($create) {
+ $sql = new Pluf_SQL('wikiresource=%s', array($this->wikiresource));
+ $rev = Pluf::factory('IDF_Wiki_ResourceRevision')->getList(array('filter'=>$sql->gen()));
+ if ($rev->count() > 1) {
+ IDF_Timeline::insert($this, $resource->get_project(), $this->get_submitter());
+ foreach ($rev as $r) {
+ if ($r->id != $this->id and $r->is_head) {
+ $r->is_head = false;
+ $r->update();
+ }
+ }
+ }
+ }
+
+ // update the modification timestamp
+ $resource->update();
+ }
+
+ function getFilePath()
+ {
+ return sprintf(Pluf::f('upload_path').'/'.$this->get_wikiresource()->get_project()->shortname.'/wiki/res/%d/%d.%s',
+ $this->get_wikiresource()->id, $this->id, $this->fileext);
+ }
+
+ function getViewURL()
+ {
+ $prj = $this->get_wikiresource()->get_project();
+ $resource = $this->get_wikiresource();
+ return Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource',
+ array($prj->shortname, $resource->title),
+ array('rev' => $this->id));
+ }
+
+ function getRawURL($attachment = false)
+ {
+ $query = $attachment ? array('attachment' => 1) : array();
+ $prj = $this->get_wikiresource()->get_project();
+ return Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::rawResource',
+ array($prj->shortname, $this->id),
+ $query);
+ }
+
+ /**
+ * Returns the page revisions which contain references to this resource revision
+ */
+ function getPageRevisions()
+ {
+ $db =& Pluf::db();
+ $sql_results = $db->select(
+ 'SELECT idf_wiki_pagerevision_id as id '.
+ 'FROM '.Pluf::f('db_table_prefix', '').'idf_wiki_pagerevision_idf_wiki_resourcerevision_assoc '.
+ 'WHERE idf_wiki_resourcerevision_id='.$this->id
+ );
+ $ids = array(0);
+ foreach ($sql_results as $id) {
+ $ids[] = $id['id'];
+ }
+ $ids = implode (',', $ids);
+
+ $sql = new Pluf_SQL('id IN ('.$ids.')');
+ return Pluf::factory('IDF_Wiki_PageRevision')
+ ->getList(array('filter' => $sql->gen()));
+ }
+
+ /**
+ * Renders the resource with the given view options, including a link to the resource' detail page
+ */
+ function render($opts = array())
+ {
+ // give some reasonable defaults
+ $opts = array_merge(array(
+ 'align' => 'left',
+ 'width' => '',
+ 'height' => '',
+ 'preview' => 'yes', // if possible
+ 'title' => '',
+ ), $opts);
+
+ $attrs = array('class="resource-container"');
+ $styles = array();
+ if (!empty($opts['align'])) {
+ switch ($opts['align']) {
+ case 'left':
+ $styles[] = 'float: left';
+ $styles[] = 'margin-right: 10px';
+ break;
+ case 'center':
+ $styles[] = 'margin: 0 auto 0 auto';
+ break;
+ case 'right':
+ $styles[] = 'float: right';
+ $styles[] = 'margin-left: 10px';
+ break;
+ }
+ }
+ if (!empty($opts['width'])) {
+ $styles[] = 'width:'.$opts['width'];
+ }
+ if (!empty($opts['height'])) {
+ $styles[] = 'height:'.$opts['height'];
+ }
+
+ $raw = $this->renderRaw();
+ $viewUrl = $this->getViewURL();
+ $download = '';
+ $html = '
+ ', $url, $resource->title);
+ }
+
+ if (preg_match('#^text/(plain|xml|html|sgml|javascript|ecmascript|css)$#', $resource->mime_type)) {
+ return sprintf('', $url, $resource->title);
+ }
+
+ return '';
+ }
+
+
+ public function timelineFragment($request)
+ {
+ $resource = $this->get_wikiresource();
+ $url = Pluf::f('url_base')
+ .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource',
+ array($request->project->shortname,
+ $resource->title),
+ array('rev' => $this->id));
+
+ $out = "\n".'
';
+ $out .= "\n".''.
+ Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
+ ' ';
+ $stag = new IDF_Template_ShowUser();
+ $user = $stag->start($this->get_submitter(), $request, '', false);
+ $out .= sprintf(__('%2$s, %3$s'), $url, Pluf_esc($resource->title), Pluf_esc($this->summary));
+ $out .= ' ';
+ return Pluf_Template::markSafe($out);
+ }
+
+ public function feedFragment($request)
+ {
+ $resource = $this->get_wikiresource();
+ $url = Pluf::f('url_base')
+ .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource',
+ array($request->project->shortname,
+ $resource->title),
+ array('rev' => $this->id));
+
+ $title = sprintf(__('%1$s: Documentation resource %2$s updated - %3$s'),
+ $request->project->name,
+ $resource->title, $resource->summary);
+ $date = Pluf_Date::gmDateToGmString($this->creation_dtime);
+ $context = new Pluf_Template_Context_Request(
+ $request,
+ array('url' => $url,
+ 'title' => $title,
+ 'resource' => $resource,
+ 'rev' => $this,
+ 'create' => false,
+ 'date' => $date)
+ );
+ $tmpl = new Pluf_Template('idf/wiki/feedfragment-resource.xml');
+ return $tmpl->render($context);
+ }
+}
diff --git a/src/IDF/conf/idf.php-dist b/src/IDF/conf/idf.php-dist
index c4424b5..97bd441 100644
--- a/src/IDF/conf/idf.php-dist
+++ b/src/IDF/conf/idf.php-dist
@@ -495,5 +495,54 @@ $cfg['idf_strong_key_check'] = false;
# always have precedence.
# $cfg['max_upload_size'] = 2097152; // Size in bytes
+# If a download archive is uploaded, the size of the archive is limited to 20MB.
+# The php.ini upload_max_filesize and post_max_size configuration setting will
+# always have precedence.
+# $cfg['max_upload_archive_size'] = 20971520; // Size in bytes
+
+# Older versions of Indefero submitted a POST request to a configured
+# post-commit web hook when new revisions arrived, whereas a PUT request
+# would have been more appropriate. Also, the payload's HMAC digest was
+# submitted as value of the HTTP header 'Post-Commit-Hook-Hmac' during
+# such a request. Since newer versions of Indefero use the same authentication
+# mechanism (based on the same secret key) for other web hooks of the same
+# project as well, the name of this HTTP header was no longer appropriate
+# and as such changed to simply 'Web-Hook-Hmac'.
+#
+# Setting the following configuration option to 'compat' now restores the
+# old behaviour in both cases. Please notice however that this compatibility
+# option is likely to go away in the next major version of Indefero, so you
+# should really change the other end of your web hooks!
+$cfg['webhook_processing'] = 'compat';
+
+# If IDF recalculates the activity index of the forge's projects, it does so
+# by looking at the created and updated items in a particular tab / section
+# for each project.
+#
+# You can now edit the weights that are applied to the calculation for each
+# section in order to give other things more precendence. For example, if you
+# do not use the documentation part to a great extent in most of your projects,
+# you can weight this section lower and get an overall better activity value.
+#
+# If a section is removed, then activity in this section is neglected during
+# the calculation. The same is true in case a section is disabled in the
+# project administration.
+$cfg['activity_section_weights'] = array(
+ 'source' => 4,
+ 'issues' => 2,
+ 'wiki' => 2,
+ 'downloads' => 1,
+ 'review' => 1,
+);
+
+# Here you can define the timespan in days how long the activity calculation
+# process should look into the history to get meaningful activity values for
+# each project.
+#
+# If you have many low-profile projects in your forge, i.e. projects that only
+# record very little activity, then it might be a good idea to bump this value
+# high enough to show a proper activity index for those projects as well.
+$cfg['activity_lookback'] = 7;
+
return $cfg;
diff --git a/src/IDF/conf/urls.php b/src/IDF/conf/urls.php
index 74bacf9..eac28ae 100644
--- a/src/IDF/conf/urls.php
+++ b/src/IDF/conf/urls.php
@@ -29,6 +29,16 @@ $ctl[] = array('regex' => '#^/$#',
'model' => 'IDF_Views',
'method' => 'index');
+$ctl[] = array('regex' => '#^/projects/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views',
+ 'method' => 'listProjects');
+
+$ctl[] = array('regex' => '#^/projects/label/(\w+)/(\w+)/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views',
+ 'method' => 'listProjectsByLabel');
+
$ctl[] = array('regex' => '#^/login/$#',
'base' => $base,
'model' => 'IDF_Views',
@@ -255,17 +265,32 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/source/changesrev/$#',
'model' => 'IDF_Views_Source_Svn',
'method' => 'changelogRev');
+$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/repo/(.*)$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Source',
+ 'method' => 'repository');
+
// ---------- WIKI -----------------------------------------
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/$#',
'base' => $base,
'model' => 'IDF_Views_Wiki',
- 'method' => 'index');
+ 'method' => 'listPages');
+
+$ctl[] = array('regex' => '#^/p/([\-\w]+)/res/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Wiki',
+ 'method' => 'listResources');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/create/$#',
'base' => $base,
'model' => 'IDF_Views_Wiki',
- 'method' => 'create');
+ 'method' => 'createPage');
+
+$ctl[] = array('regex' => '#^/p/([\-\w]+)/res/create/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Wiki',
+ 'method' => 'createResource');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/search/$#',
'base' => $base,
@@ -275,30 +300,60 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/search/$#',
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/label/(\d+)/$#',
'base' => $base,
'model' => 'IDF_Views_Wiki',
- 'method' => 'listLabel');
+ 'method' => 'listPagesWithLabel');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/update/(.*)/$#',
'base' => $base,
'model' => 'IDF_Views_Wiki',
- 'method' => 'update');
+ 'method' => 'updatePage');
+
+$ctl[] = array('regex' => '#^/p/([\-\w]+)/res/update/(.*)/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Wiki',
+ 'method' => 'updateResource');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/delrev/(\d+)/$#',
'base' => $base,
'model' => 'IDF_Views_Wiki',
- 'method' => 'deleteRev');
+ 'method' => 'deletePageRev');
+
+$ctl[] = array('regex' => '#^/p/([\-\w]+)/res/delrev/(\d+)/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Wiki',
+ 'method' => 'deleteResourceRev');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/delete/(\d+)/$#',
'base' => $base,
'model' => 'IDF_Views_Wiki',
- 'method' => 'delete');
+ 'method' => 'deletePage');
+
+$ctl[] = array('regex' => '#^/p/([\-\w]+)/res/delete/(\d+)/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Wiki',
+ 'method' => 'deleteResource');
+
+$ctl[] = array('regex' => '#^/p/([\-\w]+)/res/raw/(.*)/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Wiki',
+ 'method' => 'rawResource');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/page/(.*)/$#',
'base' => $base,
'model' => 'IDF_Views_Wiki',
- 'method' => 'view');
+ 'method' => 'viewPage');
+
+$ctl[] = array('regex' => '#^/p/([\-\w]+)/resource/(.*)/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Wiki',
+ 'method' => 'viewResource');
// ---------- Downloads ------------------------------------
+$ctl[] = array('regex' => '#^/help/archive-format/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views',
+ 'method' => 'faqArchiveFormat');
+
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/$#',
'base' => $base,
'model' => 'IDF_Views_Download',
@@ -327,7 +382,12 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/(\d+)/get/$#',
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/create/$#',
'base' => $base,
'model' => 'IDF_Views_Download',
- 'method' => 'submit');
+ 'method' => 'create');
+
+$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/create/archive/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Download',
+ 'method' => 'createFromArchive');
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/(\d+)/delete/$#',
'base' => $base,
@@ -418,6 +478,11 @@ $ctl[] = array('regex' => '#^/api/$#',
// ---------- FORGE ADMIN --------------------------------
+$ctl[] = array('regex' => '#^/admin/forge/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Admin',
+ 'method' => 'forge');
+
$ctl[] = array('regex' => '#^/admin/projects/$#',
'base' => $base,
'model' => 'IDF_Views_Admin',
@@ -428,6 +493,11 @@ $ctl[] = array('regex' => '#^/admin/projects/(\d+)/$#',
'model' => 'IDF_Views_Admin',
'method' => 'projectUpdate');
+$ctl[] = array('regex' => '#^/admin/projects/labels/$#',
+ 'base' => $base,
+ 'model' => 'IDF_Views_Admin',
+ 'method' => 'projectLabels');
+
$ctl[] = array('regex' => '#^/admin/projects/create/$#',
'base' => $base,
'model' => 'IDF_Views_Admin',
diff --git a/src/IDF/locale/idf.pot b/src/IDF/locale/idf.pot
index d1ff569..a1ce29b 100644
--- a/src/IDF/locale/idf.pot
+++ b/src/IDF/locale/idf.pot
@@ -8,31 +8,35 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-10-31 01:11+0100\n"
+"POT-Creation-Date: 2012-03-22 01:16+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME
+ \n"
+"
\n"
+"\n"
+"http://domain.com/upload
http://domain.com/upload?my%20param
\n"
+"
\n"
+"\n"
+"%p
- project name%d
- download idhttp://mydomain.com/%p/%d
would send a POST "
+"request to\n"
+"http://mydomain.com/my-project/123
.\n"
-"
\n"
"\n"
"http://domain.com/commit
http://domain.com/commit?my%20param
\n"
-"
\n"
"\n"
"%p
- project name%r
- revision numberhttp://mydomain.com/%p/%r
would send a request "
+"to\n"
+"http://mydomain.com/my-project/123
.
manifest.xml
file with meta "
+"information about the\n"
+"files to process inside the archive. All processed files must be unique or "
+"replace existing files explicitely."
+msgstr ""
+
+#: IDF/gettexttemplates/idf/downloads/createFromArchive.html.php:5
+#, php-format
+msgid ""
+"You can learn more about the archive format here."
+msgstr ""
+
+#: IDF/gettexttemplates/idf/downloads/createFromArchive.html.php:6
+msgid ""
+"The form contains some errors. Please correct them to submit the archive."
+msgstr ""
+
+#: IDF/gettexttemplates/idf/downloads/createFromArchive.html.php:7
+msgid "Submit Archive"
+msgstr ""
+
#: IDF/gettexttemplates/idf/downloads/delete.html.php:3
msgid ""
"Attention! If you want to delete a specific version of your "
@@ -1233,12 +1536,18 @@ msgstr ""
#: IDF/gettexttemplates/idf/downloads/view.html.php:4
#: IDF/gettexttemplates/idf/issues/attachment.html.php:4
#: IDF/gettexttemplates/idf/issues/view.html.php:7
-#: IDF/gettexttemplates/idf/wiki/delete.html.php:7
-#: IDF/gettexttemplates/idf/wiki/delete.html.php:8
-#: IDF/gettexttemplates/idf/wiki/deletepage.html.php:4
-#: IDF/gettexttemplates/idf/wiki/deletepage.html.php:5
-#: IDF/gettexttemplates/idf/wiki/view.html.php:8
-#: IDF/gettexttemplates/idf/wiki/view.html.php:9
+#: IDF/gettexttemplates/idf/wiki/deletePage.html.php:4
+#: IDF/gettexttemplates/idf/wiki/deletePage.html.php:5
+#: IDF/gettexttemplates/idf/wiki/deletePageRev.html.php:7
+#: IDF/gettexttemplates/idf/wiki/deletePageRev.html.php:8
+#: IDF/gettexttemplates/idf/wiki/deleteResource.html.php:6
+#: IDF/gettexttemplates/idf/wiki/deleteResource.html.php:7
+#: IDF/gettexttemplates/idf/wiki/deleteResourceRev.html.php:6
+#: IDF/gettexttemplates/idf/wiki/deleteResourceRev.html.php:7
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:8
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:9
+#: IDF/gettexttemplates/idf/wiki/viewResource.html.php:6
+#: IDF/gettexttemplates/idf/wiki/viewResource.html.php:7
#, php-format
msgid "by %%submitter%%"
msgstr ""
@@ -1247,32 +1556,6 @@ msgstr ""
msgid "Delete File"
msgstr ""
-#: IDF/gettexttemplates/idf/downloads/delete.html.php:7
-#: IDF/gettexttemplates/idf/downloads/submit.html.php:9
-#: IDF/gettexttemplates/idf/downloads/view.html.php:9
-#: IDF/gettexttemplates/idf/gadmin/projects/delete.html.php:21
-#: IDF/gettexttemplates/idf/gadmin/projects/update.html.php:16
-#: IDF/gettexttemplates/idf/gadmin/users/create.html.php:5
-#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:14
-#: IDF/gettexttemplates/idf/issues/create.html.php:14
-#: IDF/gettexttemplates/idf/issues/view.html.php:27
-#: IDF/gettexttemplates/idf/register/confirmation.html.php:7
-#: IDF/gettexttemplates/idf/register/index.html.php:8
-#: IDF/gettexttemplates/idf/register/inputkey.html.php:5
-#: IDF/gettexttemplates/idf/review/create.html.php:12
-#: IDF/gettexttemplates/idf/review/view.html.php:41
-#: IDF/gettexttemplates/idf/user/changeemail.html.php:5
-#: IDF/gettexttemplates/idf/user/myaccount.html.php:13
-#: IDF/gettexttemplates/idf/user/passrecovery-ask.html.php:5
-#: IDF/gettexttemplates/idf/user/passrecovery-inputkey.html.php:5
-#: IDF/gettexttemplates/idf/user/passrecovery.html.php:7
-#: IDF/gettexttemplates/idf/wiki/create.html.php:7
-#: IDF/gettexttemplates/idf/wiki/delete.html.php:10
-#: IDF/gettexttemplates/idf/wiki/deletepage.html.php:7
-#: IDF/gettexttemplates/idf/wiki/update.html.php:7
-msgid "Cancel"
-msgstr ""
-
#: IDF/gettexttemplates/idf/downloads/delete.html.php:8
#: IDF/gettexttemplates/idf/downloads/view.html.php:14
msgid "Uploaded:"
@@ -1282,38 +1565,46 @@ msgstr ""
#: IDF/gettexttemplates/idf/downloads/view.html.php:15
#: IDF/gettexttemplates/idf/issues/view.html.php:29
#: IDF/gettexttemplates/idf/review/view.html.php:27
-#: IDF/gettexttemplates/idf/wiki/delete.html.php:12
-#: IDF/gettexttemplates/idf/wiki/deletepage.html.php:9
-#: IDF/gettexttemplates/idf/wiki/view.html.php:15
+#: IDF/gettexttemplates/idf/wiki/deletePage.html.php:9
+#: IDF/gettexttemplates/idf/wiki/deletePageRev.html.php:12
+#: IDF/gettexttemplates/idf/wiki/deleteResource.html.php:14
+#: IDF/gettexttemplates/idf/wiki/deleteResourceRev.html.php:14
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:15
+#: IDF/gettexttemplates/idf/wiki/viewResource.html.php:17
msgid "Updated:"
msgstr ""
#: IDF/gettexttemplates/idf/downloads/delete.html.php:10
#: IDF/gettexttemplates/idf/downloads/view.html.php:16
#: IDF/gettexttemplates/idf/gadmin/projects/index.html.php:6
-#: IDF/gettexttemplates/idf/index.html.php:15
+#: IDF/gettexttemplates/idf/listProjects.html.php:17
msgid "Downloads:"
msgstr ""
#: IDF/gettexttemplates/idf/downloads/delete.html.php:11
#: IDF/gettexttemplates/idf/downloads/download-created-email.txt.php:7
+#: IDF/gettexttemplates/idf/downloads/download-updated-email.txt.php:7
#: IDF/gettexttemplates/idf/downloads/view.html.php:17
#: IDF/gettexttemplates/idf/issues/feedfragment.xml.php:6
+#: IDF/gettexttemplates/idf/issues/feedfragment.xml~.php:6
#: IDF/gettexttemplates/idf/issues/issue-created-email.txt.php:9
-#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt.php:10
-#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt.php:15
+#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt.php:11
+#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt.php:16
+#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt~.php:10
+#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt~.php:15
#: IDF/gettexttemplates/idf/issues/view.html.php:21
#: IDF/gettexttemplates/idf/issues/view.html.php:33
+#: IDF/gettexttemplates/idf/project-list.html.php:8
#: IDF/gettexttemplates/idf/review/feedfragment.xml.php:6
#: IDF/gettexttemplates/idf/review/review-created-email.txt.php:9
#: IDF/gettexttemplates/idf/review/review-updated-email.txt.php:13
-#: IDF/gettexttemplates/idf/wiki/delete.html.php:13
-#: IDF/gettexttemplates/idf/wiki/deletepage.html.php:10
-#: IDF/gettexttemplates/idf/wiki/view.html.php:16
+#: IDF/gettexttemplates/idf/wiki/deletePage.html.php:10
+#: IDF/gettexttemplates/idf/wiki/deletePageRev.html.php:13
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:16
#: IDF/gettexttemplates/idf/wiki/wiki-created-email.txt.php:7
#: IDF/gettexttemplates/idf/wiki/wiki-updated-email.txt.php:9
#: IDF/gettexttemplates/idf/wiki/wiki-updated-email.txt.php:12
-#: IDF/IssueComment.php:157 IDF/WikiRevision.php:175
+#: IDF/IssueComment.php:157 IDF/Wiki/PageRevision.php:204
msgid "Labels:"
msgstr ""
@@ -1322,8 +1613,10 @@ msgid "A new file is available for download:"
msgstr ""
#: IDF/gettexttemplates/idf/downloads/download-created-email.txt.php:4
+#: IDF/gettexttemplates/idf/downloads/download-updated-email.txt.php:4
#: IDF/gettexttemplates/idf/issues/issue-created-email.txt.php:5
-#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt.php:5
+#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt.php:6
+#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt~.php:5
#: IDF/gettexttemplates/idf/review/review-created-email.txt.php:4
#: IDF/gettexttemplates/idf/review/review-updated-email.txt.php:8
#: IDF/gettexttemplates/idf/source/commit-created-email.txt.php:4
@@ -1333,8 +1626,10 @@ msgid "Hello,"
msgstr ""
#: IDF/gettexttemplates/idf/downloads/download-created-email.txt.php:5
+#: IDF/gettexttemplates/idf/downloads/download-updated-email.txt.php:5
#: IDF/gettexttemplates/idf/issues/issue-created-email.txt.php:6
-#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt.php:6
+#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt.php:7
+#: IDF/gettexttemplates/idf/issues/issue-updated-email.txt~.php:6
#: IDF/gettexttemplates/idf/review/review-created-email.txt.php:5
#: IDF/gettexttemplates/idf/review/review-updated-email.txt.php:9
#: IDF/gettexttemplates/idf/source/commit-created-email.txt.php:6
@@ -1344,20 +1639,27 @@ msgid "Project:"
msgstr ""
#: IDF/gettexttemplates/idf/downloads/download-created-email.txt.php:6
+#: IDF/gettexttemplates/idf/downloads/download-updated-email.txt.php:6
msgid "Submitted by:"
msgstr ""
#: IDF/gettexttemplates/idf/downloads/download-created-email.txt.php:8
+#: IDF/gettexttemplates/idf/downloads/download-updated-email.txt.php:8
msgid "Download:"
msgstr ""
#: IDF/gettexttemplates/idf/downloads/download-created-email.txt.php:9
+#: IDF/gettexttemplates/idf/downloads/download-updated-email.txt.php:9
#: IDF/gettexttemplates/idf/issues/issue-created-email.txt.php:10
#: IDF/gettexttemplates/idf/review/view.html.php:31
#: IDF/gettexttemplates/idf/user/public.html.php:4
msgid "Description:"
msgstr ""
+#: IDF/gettexttemplates/idf/downloads/download-updated-email.txt.php:3
+msgid "A file download was updated:"
+msgstr ""
+
#: IDF/gettexttemplates/idf/downloads/feedfragment.xml.php:3
msgid "Details"
msgstr ""
@@ -1371,34 +1673,6 @@ msgstr ""
msgid "Number of files:"
msgstr ""
-#: IDF/gettexttemplates/idf/downloads/submit.html.php:3
-msgid ""
-"Each file must have a distinct name and file contents\n"
-"cannot be changed, so be sure to include release numbers in each file\n"
-"name."
-msgstr ""
-
-#: IDF/gettexttemplates/idf/downloads/submit.html.php:6
-#, php-format
-msgid ""
-"You can use the Markdown syntax for the description."
-msgstr ""
-
-#: IDF/gettexttemplates/idf/downloads/submit.html.php:7
-msgid "The form contains some errors. Please correct them to submit the file."
-msgstr ""
-
-#: IDF/gettexttemplates/idf/downloads/submit.html.php:8
-msgid "Submit File"
-msgstr ""
-
-#: IDF/gettexttemplates/idf/downloads/submit.html.php:10
-#: IDF/gettexttemplates/idf/register/inputkey.html.php:6
-#: IDF/gettexttemplates/idf/user/changeemail.html.php:6
-#: IDF/gettexttemplates/idf/user/passrecovery-inputkey.html.php:6
-msgid "Instructions"
-msgstr ""
-
#: IDF/gettexttemplates/idf/downloads/view.html.php:3
msgid ""
"Attention! This file is marked as deprecated, download it "
@@ -1428,8 +1702,10 @@ msgstr ""
#: IDF/gettexttemplates/idf/downloads/view.html.php:11
#: IDF/gettexttemplates/idf/gadmin/projects/update.html.php:18
-#: IDF/gettexttemplates/idf/wiki/update.html.php:9
-#: IDF/gettexttemplates/idf/wiki/view.html.php:12
+#: IDF/gettexttemplates/idf/wiki/updatePage.html.php:9
+#: IDF/gettexttemplates/idf/wiki/updateResource.html.php:7
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:12
+#: IDF/gettexttemplates/idf/wiki/viewResource.html.php:12
msgid "Trash"
msgstr ""
@@ -1438,15 +1714,17 @@ msgid "Delete this file"
msgstr ""
#: IDF/gettexttemplates/idf/faq-api.html.php:3
-#: IDF/gettexttemplates/idf/faq.html.php:34
+#: IDF/gettexttemplates/idf/faq-archive-format.html.php:3
+#: IDF/gettexttemplates/idf/faq.html.php:65
msgid "Here we are, just to help you."
msgstr ""
#: IDF/gettexttemplates/idf/faq-api.html.php:4
-#: IDF/gettexttemplates/idf/faq.html.php:35
-#: IDF/gettexttemplates/idf/gadmin/base.html.php:3
-#: IDF/gettexttemplates/idf/index.html.php:3 IDF/Views/Admin.php:57
-#: IDF/Views.php:47
+#: IDF/gettexttemplates/idf/faq-archive-format.html.php:4
+#: IDF/gettexttemplates/idf/faq.html.php:66
+#: IDF/gettexttemplates/idf/gadmin/base.html.php:4
+#: IDF/gettexttemplates/idf/index.html.php:4 IDF/Views/Admin.php:77
+#: IDF/Views.php:91
msgid "Projects"
msgstr ""
@@ -1454,137 +1732,223 @@ msgstr ""
msgid ""
"This is simple:
\n" "To embed any previously uploaded resource into your wiki page, you can "
+"use the [[!ResourceName]]
syntax.
The rendering of the resource can then be further fine-tuned:\n" +"
[[!ImageResource, align=right, width=200]]
renders "
+"\"ImageResource\" right-aligned and scale its width to 200[[!TextResource, align=center, width=300, height=300]]
"
+"renders \"TextResource\" in a centered, 300 by 300 px iframe[[!AnyResource, preview=no]]
does not render a preview of "
+"the resource, but only provides a download link (default for binary "
+"resources)[[!BinaryResource, title=Download]]
renders the download "
+"link of \"BinaryResource\" with an alternative titleIf you have to publish many files at once for a new release, it is a very " +"tedious task\n" +"to upload them one after another and enter meta information like a summary, " +"a description or additional\n" +"labels for each of them.
\n" +"InDefero therefore supports a special archive format that is basically a " +"standard zip file which comes with\n" +"some meta information. These meta information are kept in a special manifest " +"file, which is distinctly kept from\n" +"the rest of the files in the archive that should be published.
\n" +"Once this archive has been uploaded, InDefero reads in the meta " +"information, unpacks the other files from\n" +"the archive and creates new individual downloads for each of them.
" +msgstr "" + +#: IDF/gettexttemplates/idf/faq.html.php:36 +#, php-format +msgid "Learn more about the archive format." +msgstr "" + +#: IDF/gettexttemplates/idf/faq.html.php:37 msgid "" "The API (Application Programming Interface) is used to interact with " "InDefero with another program. For example, this can be used to create a " "desktop program to submit new tickets easily." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:11 +#: IDF/gettexttemplates/idf/faq.html.php:38 #, php-format msgid "Learn more about the API." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:12 -#: IDF/gettexttemplates/idf/faq.html.php:16 +#: IDF/gettexttemplates/idf/faq.html.php:39 +#: IDF/gettexttemplates/idf/faq.html.php:45 msgid "What are the keyboard shortcuts?" msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:13 -#: IDF/gettexttemplates/idf/faq.html.php:31 +#: IDF/gettexttemplates/idf/faq.html.php:40 +#: IDF/gettexttemplates/idf/faq.html.php:60 msgid "How to mark an issue as duplicate?" msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:14 -#: IDF/gettexttemplates/idf/faq.html.php:32 +#: IDF/gettexttemplates/idf/faq.html.php:41 +#: IDF/gettexttemplates/idf/faq.html.php:61 msgid "How can I display my head next to my comments?" msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:15 -#: IDF/gettexttemplates/idf/faq.html.php:33 +#: IDF/gettexttemplates/idf/faq.html.php:42 +#: IDF/gettexttemplates/idf/faq.html.php:62 +msgid "How can I embed images and other resources in my documentation pages?" +msgstr "" + +#: IDF/gettexttemplates/idf/faq.html.php:43 +#: IDF/gettexttemplates/idf/faq.html.php:63 +msgid "What is this \"Upload Archive\" functionality about?" +msgstr "" + +#: IDF/gettexttemplates/idf/faq.html.php:44 +#: IDF/gettexttemplates/idf/faq.html.php:64 msgid "What is the API and how is it used?" msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:17 +#: IDF/gettexttemplates/idf/faq.html.php:46 msgid "Shift+h: This help page." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:18 +#: IDF/gettexttemplates/idf/faq.html.php:47 msgid "If you are in a project, you have the following shortcuts:" msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:19 +#: IDF/gettexttemplates/idf/faq.html.php:48 msgid "Shift+u: Project updates." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:20 +#: IDF/gettexttemplates/idf/faq.html.php:49 msgid "Shift+d: Downloads." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:21 +#: IDF/gettexttemplates/idf/faq.html.php:50 msgid "Shift+o: Documentation." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:22 +#: IDF/gettexttemplates/idf/faq.html.php:51 msgid "Shift+a: Create a new issue." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:23 +#: IDF/gettexttemplates/idf/faq.html.php:52 msgid "Shift+i: List of open issues." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:24 +#: IDF/gettexttemplates/idf/faq.html.php:53 msgid "Shift+m: The issues you submitted." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:25 +#: IDF/gettexttemplates/idf/faq.html.php:54 msgid "Shift+w: The issues assigned to you." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:26 +#: IDF/gettexttemplates/idf/faq.html.php:55 msgid "Shift+s: Source." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:27 +#: IDF/gettexttemplates/idf/faq.html.php:56 msgid "You also have the standard access keys:" msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:28 +#: IDF/gettexttemplates/idf/faq.html.php:57 msgid "Alt+1: Home." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:29 +#: IDF/gettexttemplates/idf/faq.html.php:58 msgid "Alt+2: Skip the menus." msgstr "" -#: IDF/gettexttemplates/idf/faq.html.php:30 +#: IDF/gettexttemplates/idf/faq.html.php:59 msgid "Alt+4: Search (when available)." msgstr "" -#: IDF/gettexttemplates/idf/gadmin/base.html.php:4 -msgid "People" +#: IDF/gettexttemplates/idf/gadmin/base.html.php:3 +msgid "Forge" msgstr "" #: IDF/gettexttemplates/idf/gadmin/base.html.php:5 +msgid "People" +msgstr "" + +#: IDF/gettexttemplates/idf/gadmin/base.html.php:6 msgid "Usher" msgstr "" -#: IDF/gettexttemplates/idf/gadmin/home.html.php:3 -msgid "You have here access to the administration of the forge." +#: IDF/gettexttemplates/idf/gadmin/forge/base.html.php:3 +msgid "Frontpage" msgstr "" -#: IDF/gettexttemplates/idf/gadmin/home.html.php:4 -#: IDF/gettexttemplates/idf/project/home.html.php:3 -#: IDF/gettexttemplates/idf/project/timeline.html.php:4 -msgid "Welcome" +#: IDF/gettexttemplates/idf/gadmin/forge/index.html.php:3 +#, php-format +msgid "" +"\n" +"Instructions:
\n" +"You can set up a custom forge page that is used as entry page for the " +"forge instead of the plain project listing. This page is then also " +"accessible via the 'Home' link in main menu bar.
\n" +"The content of the page can use the Markdown syntax" +"a> with the Extra extension.
\n" +"Additionally, the following macros are available:
\n"
+"
{projectlist, label=..., order=(name|activity), limit=...}"
+"code> - Renders a project list that can optionally be filtered by label, "
+"ordered by 'name' or 'activity' and / or limited to a specific number of "
+"projects.
The content of the page can use the Markdown syntax" "a> with the Extra extension.
\n" "Website addresses are automatically linked and you can link to another " -"page in the documentation using double square brackets like that " -"[[AnotherPage]].
\n" +"page in the documentation using double square brackets like that"
+"[[AnotherPage]]
.\n"
+"If you want to embed uploaded resources, use the [[!ResourceName]]"
+"code> syntax for that. This is described more in detail in the FAQ.
To directly include a file content from the repository, embrace its path " -"with triple square brackets: [[[path/to/file.txt]]].
\n" +"with triple square brackets:[[[my/file.txt]]]
.\n"
msgstr ""
-#: IDF/gettexttemplates/idf/wiki/index.html.php:3
+#: IDF/gettexttemplates/idf/wiki/feedfragment-resource.xml.php:4
+msgid "Initial creation"
+msgstr ""
+
+#: IDF/gettexttemplates/idf/wiki/listPages.html.php:3
#, php-format
msgid "See the deprecated pages."
msgstr ""
-#: IDF/gettexttemplates/idf/wiki/index.html.php:5
+#: IDF/gettexttemplates/idf/wiki/listPages.html.php:5
msgid "Number of pages:"
msgstr ""
+#: IDF/gettexttemplates/idf/wiki/listResources.html.php:4
+msgid "Number of resources:"
+msgstr ""
+
#: IDF/gettexttemplates/idf/wiki/search.html.php:4
msgid "Pages found:"
msgstr ""
-#: IDF/gettexttemplates/idf/wiki/update.html.php:4
+#: IDF/gettexttemplates/idf/wiki/updatePage.html.php:4
+#: IDF/gettexttemplates/idf/wiki/updateResource.html.php:3
msgid "The form contains some errors. Please correct them to update the page."
msgstr ""
-#: IDF/gettexttemplates/idf/wiki/update.html.php:6
+#: IDF/gettexttemplates/idf/wiki/updatePage.html.php:6
msgid "Update Page"
msgstr ""
-#: IDF/gettexttemplates/idf/wiki/update.html.php:8
-#: IDF/gettexttemplates/idf/wiki/update.html.php:10
-#: IDF/gettexttemplates/idf/wiki/update.html.php:11
+#: IDF/gettexttemplates/idf/wiki/updatePage.html.php:8
+#: IDF/gettexttemplates/idf/wiki/updatePage.html.php:10
+#: IDF/gettexttemplates/idf/wiki/updatePage.html.php:11
msgid "Delete this page"
msgstr ""
-#: IDF/gettexttemplates/idf/wiki/view.html.php:3
+#: IDF/gettexttemplates/idf/wiki/updateResource.html.php:4
+msgid "Update Resource"
+msgstr ""
+
+#: IDF/gettexttemplates/idf/wiki/updateResource.html.php:6
+#: IDF/gettexttemplates/idf/wiki/updateResource.html.php:8
+#: IDF/gettexttemplates/idf/wiki/updateResource.html.php:9
+msgid "Delete this resource"
+msgstr ""
+
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:3
msgid ""
"Attention! This page is marked as deprecated, \n"
"use it as reference only if you are sure you need these specific information."
msgstr ""
-#: IDF/gettexttemplates/idf/wiki/view.html.php:5
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:5
#, php-format
msgid ""
"You are looking at an old revision of the page \n"
@@ -3426,15 +4032,33 @@ msgid ""
"by %%submitter%%."
msgstr ""
-#: IDF/gettexttemplates/idf/wiki/view.html.php:10
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:10
msgid "Table of Content"
msgstr ""
-#: IDF/gettexttemplates/idf/wiki/view.html.php:11
-#: IDF/gettexttemplates/idf/wiki/view.html.php:13
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:11
+#: IDF/gettexttemplates/idf/wiki/viewPage.html.php:13
+#: IDF/gettexttemplates/idf/wiki/viewResource.html.php:11
+#: IDF/gettexttemplates/idf/wiki/viewResource.html.php:13
msgid "Delete this revision"
msgstr ""
+#: IDF/gettexttemplates/idf/wiki/viewResource.html.php:3
+#, php-format
+msgid ""
+"You are looking at an old revision of the resource \n"
+"%%resource.title%%. This revision was created\n"
+"by %%submitter%%."
+msgstr ""
+
+#: IDF/gettexttemplates/idf/wiki/viewResource.html.php:14
+msgid "Page Usage"
+msgstr ""
+
+#: IDF/gettexttemplates/idf/wiki/viewResource.html.php:15
+msgid "This resource is not used on any pages yet."
+msgstr ""
+
#: IDF/gettexttemplates/idf/wiki/wiki-created-email.txt.php:3
msgid "A new documentation page has been created:"
msgstr ""
@@ -3460,7 +4084,7 @@ msgstr ""
msgid "owner"
msgstr ""
-#: IDF/Issue.php:84 IDF/WikiPage.php:86
+#: IDF/Issue.php:84 IDF/Wiki/Page.php:86
msgid "interested users"
msgstr ""
@@ -3469,12 +4093,13 @@ msgid ""
"Interested users will get an email notification when the issue is changed."
msgstr ""
-#: IDF/Issue.php:92 IDF/Review.php:95 IDF/Upload.php:99 IDF/WikiPage.php:94
+#: IDF/Issue.php:92 IDF/Project.php:94 IDF/Review.php:95 IDF/Upload.php:99
+#: IDF/Wiki/Page.php:94
msgid "labels"
msgstr ""
#: IDF/Issue.php:111 IDF/IssueFile.php:102 IDF/Review.php:114
-#: IDF/Upload.php:118 IDF/WikiPage.php:106
+#: IDF/Upload.php:118 IDF/Wiki/Page.php:106 IDF/Wiki/Resource.php:101
msgid "modification date"
msgstr ""
@@ -3486,22 +4111,22 @@ msgstr ""
#: IDF/Issue.php:214
#, php-format
-msgid "Creation of issue %d, by %s"
+msgid "Creation of issue %3$d, by %4$s"
msgstr ""
#: IDF/Issue.php:224
#, php-format
-msgid "%s: Issue %d created - %s"
+msgid "%1$s: Issue %2$d created - %3$s"
msgstr ""
-#: IDF/Issue.php:290
+#: IDF/Issue.php:307
#, php-format
-msgid "Issue %s - %s (%s)"
+msgid "Issue %1$s - %2$s (%3$s)"
msgstr ""
-#: IDF/Issue.php:336
+#: IDF/Issue.php:311
#, php-format
-msgid "Updated Issue %s - %s (%s)"
+msgid "Updated Issue %1$s - %2$s (%3$s)"
msgstr ""
#: IDF/IssueComment.php:51 IDF/IssueRelation.php:47
@@ -3514,7 +4139,7 @@ msgid "comment"
msgstr ""
#: IDF/IssueComment.php:72 IDF/Review/Comment.php:75 IDF/Upload.php:63
-#: IDF/WikiRevision.php:85
+#: IDF/Wiki/PageRevision.php:85
msgid "changes"
msgstr ""
@@ -3524,12 +4149,12 @@ msgstr ""
#: IDF/IssueComment.php:180
#, php-format
-msgid "Comment on issue %d, by %s"
+msgid "Comment on issue %3$d, by %4$s"
msgstr ""
#: IDF/IssueComment.php:191
#, php-format
-msgid "%s: Comment on issue %d - %s"
+msgid "%1$s: Comment on issue %2$d - %3$s"
msgstr ""
#: IDF/IssueFile.php:64
@@ -3637,7 +4262,7 @@ msgstr ""
#: IDF/Plugin/SyncMonotone.php:309 IDF/Plugin/SyncMonotone.php:525
#, php-format
-msgid "Could not parse usher configuration in \"%s\": %s"
+msgid "Could not parse usher configuration in \"%1$s\": %2$s"
msgstr ""
#: IDF/Plugin/SyncMonotone.php:320
@@ -3682,7 +4307,7 @@ msgstr ""
#: IDF/Plugin/SyncMonotone.php:599 IDF/Plugin/SyncMonotone.php:718
#, php-format
-msgid "Could not parse read-permissions for project \"%s\": %s"
+msgid "Could not parse read-permissions for project \"%1$s\": %2$s"
msgstr ""
#: IDF/Plugin/SyncMonotone.php:643 IDF/Plugin/SyncMonotone.php:741
@@ -3719,7 +4344,7 @@ msgstr ""
#: IDF/Project.php:70
msgid ""
-"Used in the url to access the project, must be short with only letters and "
+"Used in the URL to access the project, must be short with only letters and "
"numbers."
msgstr ""
@@ -3732,18 +4357,26 @@ msgid "description"
msgstr ""
#: IDF/Project.php:87
-msgid "The description can be extended using the markdown syntax."
+msgid "The description can be extended using the Markdown syntax."
msgstr ""
-#: IDF/Project.php:93
+#: IDF/Project.php:100
msgid "private"
msgstr ""
-#: IDF/Project.php:130
+#: IDF/Project.php:108
+msgid "current project activity"
+msgstr ""
+
+#: IDF/Project.php:159
#, php-format
msgid "Project \"%s\" not found."
msgstr ""
+#: IDF/ProjectActivity.php:56
+msgid "date"
+msgstr ""
+
#: IDF/Review/Comment.php:55 IDF/Review/Patch.php:80
msgid "patch"
msgstr ""
@@ -3760,17 +4393,17 @@ msgstr ""
#: IDF/Review/Comment.php:141
#, php-format
-msgid "Update of review %d, by %s"
+msgid "Update of review %3$d, by %4$s"
msgstr ""
#: IDF/Review/Comment.php:151
#, php-format
-msgid "%s: Updated review %d - %s"
+msgid "%1$s: Updated review %2$d - %3$s"
msgstr ""
-#: IDF/Review/Comment.php:216
+#: IDF/Review/Comment.php:222
#, php-format
-msgid "Updated Code Review %s - %s (%s)"
+msgid "Updated Code Review %1$s - %2$s (%3$s)"
msgstr ""
#: IDF/Review/Patch.php:52
@@ -3783,17 +4416,17 @@ msgstr ""
#: IDF/Review/Patch.php:153
#, php-format
-msgid "Creation of review %d, by %s"
+msgid "Creation of review %3$d, by %4$s"
msgstr ""
#: IDF/Review/Patch.php:163
#, php-format
-msgid "%s: Creation of Review %d - %s"
+msgid "%1$s: Creation of Review %2$d - %3$s"
msgstr ""
-#: IDF/Review/Patch.php:204
+#: IDF/Review/Patch.php:208
#, php-format
-msgid "New Code Review %s - %s (%s)"
+msgid "New Code Review %1$s - %2$s (%3$s)"
msgstr ""
#: IDF/Scm/Git.php:309 IDF/Scm/Mercurial.php:199
@@ -3821,7 +4454,7 @@ msgid "Could not write client key \"%s\""
msgstr ""
#: IDF/Search/Occ.php:33
-msgid "occurence"
+msgid "occurrence"
msgstr ""
#: IDF/Search/Occ.php:49
@@ -3829,11 +4462,11 @@ msgid "word"
msgstr ""
#: IDF/Search/Occ.php:75
-msgid "occurences"
+msgid "occurrences"
msgstr ""
#: IDF/Search/Occ.php:81
-msgid "ponderated occurence"
+msgid "ponderated occurrence"
msgstr ""
#: IDF/Tag.php:59
@@ -3852,10 +4485,26 @@ msgstr ""
msgid "Lower case version of the name for fast searching."
msgstr ""
-#: IDF/Template/Markdown.php:75
+#: IDF/Template/Markdown.php:84
msgid "Create this documentation page"
msgstr ""
+#: IDF/Template/Markdown.php:97
+msgid "You are not allowed to access the wiki."
+msgstr ""
+
+#: IDF/Template/Markdown.php:106
+msgid "The wiki resource has not been found."
+msgstr ""
+
+#: IDF/Template/Markdown.php:113
+msgid "The wiki resource has not been found. Create it!"
+msgstr ""
+
+#: IDF/Template/Markdown.php:146
+msgid "This revision of the resource is no longer available."
+msgstr ""
+
#: IDF/Template/ShowUser.php:51
msgid "Anonymous"
msgstr ""
@@ -3876,7 +4525,7 @@ msgstr ""
msgid "The path is relative to the upload path."
msgstr ""
-#: IDF/Upload.php:78
+#: IDF/Upload.php:78 IDF/Wiki/ResourceRevision.php:71
msgid "file size in bytes"
msgstr ""
@@ -3895,144 +4544,158 @@ msgstr ""
#: IDF/Upload.php:204
#, php-format
-msgid "Addition of download %d, by %s"
+msgid "Addition of download %2$d, by %3$s"
msgstr ""
#: IDF/Upload.php:214
#, php-format
-msgid "%s: Download %d added - %s"
+msgid "%1$s: Download %2$d added - %3$s"
msgstr ""
-#: IDF/Upload.php:256
+#: IDF/Upload.php:301
#, php-format
-msgid "New download - %s (%s)"
+msgid "New download - %1$s (%2$s)"
msgstr ""
-#: IDF/Views/Admin.php:60
+#: IDF/Upload.php:305
+#, php-format
+msgid "Updated download - %1$s (%2$s)"
+msgstr ""
+
+#: IDF/Views/Admin.php:47
+msgid "The forge configuration has been saved."
+msgstr ""
+
+#: IDF/Views/Admin.php:80
msgid "This table shows the projects in the forge."
msgstr ""
-#: IDF/Views/Admin.php:65
+#: IDF/Views/Admin.php:85
msgid "Short Name"
msgstr ""
-#: IDF/Views/Admin.php:67
+#: IDF/Views/Admin.php:87
msgid "Repository Size"
msgstr ""
-#: IDF/Views/Admin.php:73
+#: IDF/Views/Admin.php:93
msgid "No projects were found."
msgstr ""
-#: IDF/Views/Admin.php:93 IDF/Views/Admin.php:251 IDF/Views/Wiki.php:310
+#: IDF/Views/Admin.php:116
+msgid "The label configuration has been saved."
+msgstr ""
+
+#: IDF/Views/Admin.php:147 IDF/Views/Admin.php:314 IDF/Views/Wiki.php:484
+#: IDF/Views/Wiki.php:536
#, php-format
msgid "Update %s"
msgstr ""
-#: IDF/Views/Admin.php:101 IDF/Views/Project.php:302
+#: IDF/Views/Admin.php:155 IDF/Views/Project.php:304
msgid "The project has been updated."
msgstr ""
-#: IDF/Views/Admin.php:134
+#: IDF/Views/Admin.php:192
msgid "The project has been created."
msgstr ""
-#: IDF/Views/Admin.php:160
+#: IDF/Views/Admin.php:223
#, php-format
msgid "Delete %s Project"
msgstr ""
-#: IDF/Views/Admin.php:167
+#: IDF/Views/Admin.php:230
msgid "The project has been deleted."
msgstr ""
-#: IDF/Views/Admin.php:197
+#: IDF/Views/Admin.php:260
msgid "Not Validated User List"
msgstr ""
-#: IDF/Views/Admin.php:205
+#: IDF/Views/Admin.php:268
msgid "This table shows the users in the forge."
msgstr ""
-#: IDF/Views/Admin.php:209
+#: IDF/Views/Admin.php:272
msgid "login"
msgstr ""
-#: IDF/Views/Admin.php:212
+#: IDF/Views/Admin.php:275
msgid "Admin"
msgstr ""
-#: IDF/Views/Admin.php:214
+#: IDF/Views/Admin.php:277
msgid "Last Login"
msgstr ""
-#: IDF/Views/Admin.php:221
+#: IDF/Views/Admin.php:284
msgid "No users were found."
msgstr ""
-#: IDF/Views/Admin.php:258
+#: IDF/Views/Admin.php:321
msgid "You do not have the rights to update this user."
msgstr ""
-#: IDF/Views/Admin.php:276
+#: IDF/Views/Admin.php:339
msgid "The user has been updated."
msgstr ""
-#: IDF/Views/Admin.php:309
+#: IDF/Views/Admin.php:372
#, php-format
msgid "The user %s has been created."
msgstr ""
-#: IDF/Views/Admin.php:316
+#: IDF/Views/Admin.php:379
msgid "Add User"
msgstr ""
-#: IDF/Views/Admin.php:332
+#: IDF/Views/Admin.php:395
msgid "Usher management"
msgstr ""
-#: IDF/Views/Admin.php:369
+#: IDF/Views/Admin.php:432
msgid "Usher configuration has been reloaded"
msgstr ""
-#: IDF/Views/Admin.php:373
+#: IDF/Views/Admin.php:436
msgid "Usher has been shut down"
msgstr ""
-#: IDF/Views/Admin.php:378
+#: IDF/Views/Admin.php:441
msgid "Usher has been started up"
msgstr ""
-#: IDF/Views/Admin.php:416
+#: IDF/Views/Admin.php:479
#, php-format
msgid "The server \"%s\" has been started"
msgstr ""
-#: IDF/Views/Admin.php:420
+#: IDF/Views/Admin.php:483
#, php-format
msgid "The server \"%s\" has been stopped"
msgstr ""
-#: IDF/Views/Admin.php:425
+#: IDF/Views/Admin.php:488
#, php-format
msgid "The server \"%s\" has been killed"
msgstr ""
-#: IDF/Views/Admin.php:445
+#: IDF/Views/Admin.php:508
#, php-format
msgid "Open connections for \"%s\""
msgstr ""
-#: IDF/Views/Admin.php:450
+#: IDF/Views/Admin.php:513
#, php-format
msgid "no connections for server \"%s\""
msgstr ""
-#: IDF/Views/Admin.php:471
+#: IDF/Views/Admin.php:534
msgid "Yes"
msgstr ""
-#: IDF/Views/Admin.php:471
+#: IDF/Views/Admin.php:534
msgid "No"
msgstr ""
@@ -4045,11 +4708,11 @@ msgstr ""
msgid "This table shows the files to download."
msgstr ""
-#: IDF/Views/Download.php:67 IDF/Views/Download.php:315
+#: IDF/Views/Download.php:67 IDF/Views/Download.php:349
msgid "Uploaded"
msgstr ""
-#: IDF/Views/Download.php:71 IDF/Views/Download.php:319
+#: IDF/Views/Download.php:71 IDF/Views/Download.php:353
msgid "No downloads were found."
msgstr ""
@@ -4072,17 +4735,25 @@ msgstr ""
msgid "The file has been deleted."
msgstr ""
-#: IDF/Views/Download.php:243
+#: IDF/Views/Download.php:244
#, php-format
msgid "The file has been uploaded."
msgstr ""
-#: IDF/Views/Download.php:297
+#: IDF/Views/Download.php:271
+msgid "New Downloads from Archive"
+msgstr ""
+
+#: IDF/Views/Download.php:278
+msgid "The archive has been uploaded and processed."
+msgstr ""
+
+#: IDF/Views/Download.php:331
#, php-format
msgid "%1$s Downloads with Label %2$s"
msgstr ""
-#: IDF/Views/Download.php:307
+#: IDF/Views/Download.php:341
#, php-format
msgid "This table shows the downloads with label %s."
msgstr ""
@@ -4092,25 +4763,25 @@ msgstr ""
msgid "%s Open Issues"
msgstr ""
-#: IDF/Views/Issue.php:51 IDF/Views/Issue.php:379 IDF/Views/User.php:75
+#: IDF/Views/Issue.php:51 IDF/Views/Issue.php:382 IDF/Views/User.php:75
msgid "This table shows the open issues."
msgstr ""
-#: IDF/Views/Issue.php:61 IDF/Views/Issue.php:217 IDF/Views/Issue.php:298
-#: IDF/Views/Issue.php:387 IDF/Views/Issue.php:539 IDF/Views/Issue.php:762
-#: IDF/Views/Issue.php:821 IDF/Views/Review.php:57 IDF/Views/User.php:81
+#: IDF/Views/Issue.php:61 IDF/Views/Issue.php:220 IDF/Views/Issue.php:301
+#: IDF/Views/Issue.php:390 IDF/Views/Issue.php:542 IDF/Views/Issue.php:765
+#: IDF/Views/Issue.php:824 IDF/Views/Review.php:57 IDF/Views/User.php:81
msgid "Id"
msgstr ""
-#: IDF/Views/Issue.php:64 IDF/Views/Issue.php:220 IDF/Views/Issue.php:302
-#: IDF/Views/Issue.php:390 IDF/Views/Issue.php:542 IDF/Views/Issue.php:765
-#: IDF/Views/Issue.php:824 IDF/Views/Review.php:60 IDF/Views/User.php:85
+#: IDF/Views/Issue.php:64 IDF/Views/Issue.php:223 IDF/Views/Issue.php:305
+#: IDF/Views/Issue.php:393 IDF/Views/Issue.php:545 IDF/Views/Issue.php:768
+#: IDF/Views/Issue.php:827 IDF/Views/Review.php:60 IDF/Views/User.php:85
msgid "Last Updated"
msgstr ""
-#: IDF/Views/Issue.php:68 IDF/Views/Issue.php:224 IDF/Views/Issue.php:306
-#: IDF/Views/Issue.php:394 IDF/Views/Issue.php:546 IDF/Views/Issue.php:769
-#: IDF/Views/Issue.php:828
+#: IDF/Views/Issue.php:68 IDF/Views/Issue.php:227 IDF/Views/Issue.php:309
+#: IDF/Views/Issue.php:397 IDF/Views/Issue.php:549 IDF/Views/Issue.php:772
+#: IDF/Views/Issue.php:831
msgid "No issues were found."
msgstr ""
@@ -4118,142 +4789,142 @@ msgstr ""
msgid "Not assigned"
msgstr ""
-#: IDF/Views/Issue.php:146
+#: IDF/Views/Issue.php:149
#, php-format
msgid "Summary of tracked issues in %s."
msgstr ""
-#: IDF/Views/Issue.php:191
+#: IDF/Views/Issue.php:194
#, php-format
msgid "Watch List: Closed Issues for %s"
msgstr ""
-#: IDF/Views/Issue.php:192
+#: IDF/Views/Issue.php:195
#, php-format
msgid "This table shows the closed issues in your watch list for %s project."
msgstr ""
-#: IDF/Views/Issue.php:197
+#: IDF/Views/Issue.php:200
#, php-format
msgid "Watch List: Open Issues for %s"
msgstr ""
-#: IDF/Views/Issue.php:198
+#: IDF/Views/Issue.php:201
#, php-format
msgid "This table shows the open issues in your watch list for %s project."
msgstr ""
-#: IDF/Views/Issue.php:274
+#: IDF/Views/Issue.php:277
msgid "Watch List: Closed Issues"
msgstr ""
-#: IDF/Views/Issue.php:275
+#: IDF/Views/Issue.php:278
msgid "This table shows the closed issues in your watch list."
msgstr ""
-#: IDF/Views/Issue.php:280
+#: IDF/Views/Issue.php:283
msgid "Watch List: Open Issues"
msgstr ""
-#: IDF/Views/Issue.php:281
+#: IDF/Views/Issue.php:284
msgid "This table shows the open issues in your watch list."
msgstr ""
-#: IDF/Views/Issue.php:300 IDF/Views/User.php:82
+#: IDF/Views/Issue.php:303 IDF/Views/User.php:82
msgid "Project"
msgstr ""
-#: IDF/Views/Issue.php:341
+#: IDF/Views/Issue.php:344
#, php-format
-msgid "%s %s Submitted %s Issues"
+msgid "%1$s %2$s Submitted %3$s Issues"
msgstr ""
-#: IDF/Views/Issue.php:345
+#: IDF/Views/Issue.php:348
#, php-format
-msgid "%s %s Closed Submitted %s Issues"
+msgid "%1$s %2$s Closed Submitted %3$s Issues"
msgstr ""
-#: IDF/Views/Issue.php:349
+#: IDF/Views/Issue.php:352
#, php-format
-msgid "%s %s Closed Working %s Issues"
+msgid "%1$s %2$s Closed Working %3$s Issues"
msgstr ""
-#: IDF/Views/Issue.php:353
+#: IDF/Views/Issue.php:356
#, php-format
-msgid "%s %s Working %s Issues"
+msgid "%1$s %2$s Working %3$s Issues"
msgstr ""
-#: IDF/Views/Issue.php:414
+#: IDF/Views/Issue.php:417
msgid "Submit a new issue"
msgstr ""
-#: IDF/Views/Issue.php:430
+#: IDF/Views/Issue.php:433
#, php-format
-msgid "Issue %d has been created."
+msgid "Issue %2$d has been created."
msgstr ""
-#: IDF/Views/Issue.php:487
+#: IDF/Views/Issue.php:490
#, php-format
msgid "Search issues - %s"
msgstr ""
-#: IDF/Views/Issue.php:489
+#: IDF/Views/Issue.php:492
#, php-format
msgid "Search closed issues - %s"
msgstr ""
-#: IDF/Views/Issue.php:536
+#: IDF/Views/Issue.php:539
msgid "This table shows the found issues."
msgstr ""
-#: IDF/Views/Issue.php:601
+#: IDF/Views/Issue.php:604
#, php-format
-msgid "Issue %d: %s"
+msgid "Issue %2$d: %3$s"
msgstr ""
-#: IDF/Views/Issue.php:625
+#: IDF/Views/Issue.php:628
#, php-format
-msgid "Issue %d has been updated."
+msgid "Issue %2$d has been updated."
msgstr ""
-#: IDF/Views/Issue.php:715
+#: IDF/Views/Issue.php:718
#, php-format
msgid "View %s"
msgstr ""
-#: IDF/Views/Issue.php:742
+#: IDF/Views/Issue.php:745
#, php-format
msgid "%s Closed Issues"
msgstr ""
-#: IDF/Views/Issue.php:752
+#: IDF/Views/Issue.php:755
msgid "This table shows the closed issues."
msgstr ""
-#: IDF/Views/Issue.php:795
-#, php-format
-msgid "%1$s Issues with Label %2$s"
-msgstr ""
-
#: IDF/Views/Issue.php:798
#, php-format
+msgid "%1$s Issues with Label %2$s"
+msgstr ""
+
+#: IDF/Views/Issue.php:801
+#, php-format
msgid "%1$s Closed Issues with Label %2$s"
msgstr ""
-#: IDF/Views/Issue.php:811
+#: IDF/Views/Issue.php:814
#, php-format
msgid "This table shows the issues with label %s."
msgstr ""
-#: IDF/Views/Issue.php:934
+#: IDF/Views/Issue.php:937
msgid "The issue has been removed from your watch list."
msgstr ""
-#: IDF/Views/Issue.php:937
+#: IDF/Views/Issue.php:940
msgid "The issue has been added to your watch list."
msgstr ""
-#: IDF/Views/Issue.php:1035
+#: IDF/Views/Issue.php:1037
msgid "On your watch list."
msgstr ""
@@ -4269,74 +4940,75 @@ msgstr ""
msgid "Reviews and Patches"
msgstr ""
-#: IDF/Views/Project.php:178
+#: IDF/Views/Project.php:180
msgid "This table shows the project updates."
msgstr ""
-#: IDF/Views/Project.php:189
+#: IDF/Views/Project.php:191
msgid "Change"
msgstr ""
-#: IDF/Views/Project.php:193
+#: IDF/Views/Project.php:195
msgid "No changes were found."
msgstr ""
-#: IDF/Views/Project.php:294
+#: IDF/Views/Project.php:296
#, php-format
msgid "%s Project Summary"
msgstr ""
-#: IDF/Views/Project.php:329
+#: IDF/Views/Project.php:335
#, php-format
msgid "%s Issue Tracking Configuration"
msgstr ""
-#: IDF/Views/Project.php:338
+#: IDF/Views/Project.php:344
msgid "The issue tracking configuration has been saved."
msgstr ""
-#: IDF/Views/Project.php:375
+#: IDF/Views/Project.php:381
#, php-format
msgid "%s Downloads Configuration"
msgstr ""
-#: IDF/Views/Project.php:384
+#: IDF/Views/Project.php:393
msgid "The downloads configuration has been saved."
msgstr ""
-#: IDF/Views/Project.php:418
+#: IDF/Views/Project.php:428
#, php-format
msgid "%s Documentation Configuration"
msgstr ""
-#: IDF/Views/Project.php:427
+#: IDF/Views/Project.php:437
msgid "The documentation configuration has been saved."
msgstr ""
-#: IDF/Views/Project.php:461
+#: IDF/Views/Project.php:471
#, php-format
msgid "%s Project Members"
msgstr ""
-#: IDF/Views/Project.php:470
+#: IDF/Views/Project.php:480
msgid "The project membership has been saved."
msgstr ""
-#: IDF/Views/Project.php:493
+#: IDF/Views/Project.php:503
#, php-format
msgid "%s Tabs Access Rights"
msgstr ""
-#: IDF/Views/Project.php:507
-msgid "The project tabs access rights have been saved."
+#: IDF/Views/Project.php:517
+msgid ""
+"The project tabs access rights and notification settings have been saved."
msgstr ""
-#: IDF/Views/Project.php:553
+#: IDF/Views/Project.php:566
#, php-format
msgid "%s Source"
msgstr ""
-#: IDF/Views/Project.php:567
+#: IDF/Views/Project.php:580
msgid "The project source configuration has been saved."
msgstr ""
@@ -4355,17 +5027,17 @@ msgstr ""
#: IDF/Views/Review.php:94
#, php-format
-msgid "The code review %d has been created."
+msgid "The code review %2$d has been created."
msgstr ""
#: IDF/Views/Review.php:140
#, php-format
-msgid "Review %d: %s"
+msgid "Review %2$d: %3$s"
msgstr ""
#: IDF/Views/Review.php:160
#, php-format
-msgid "Your code review %d has been published."
+msgid "Your code review %2$d has been published."
msgstr ""
#: IDF/Views/Source.php:40
@@ -4388,19 +5060,19 @@ msgstr ""
msgid "%1$s %2$s Change Log"
msgstr ""
-#: IDF/Views/Source.php:147 IDF/Views/Source.php:228 IDF/Views/Source.php:356
+#: IDF/Views/Source.php:153 IDF/Views/Source.php:234 IDF/Views/Source.php:362
#, php-format
msgid "%1$s %2$s Source Tree"
msgstr ""
-#: IDF/Views/Source.php:304
+#: IDF/Views/Source.php:310
#, php-format
msgid "%s Commit Details"
msgstr ""
-#: IDF/Views/Source.php:305
+#: IDF/Views/Source.php:311
#, php-format
-msgid "%s Commit Details - %s"
+msgid "%1$s Commit Details - %2$s"
msgstr ""
#: IDF/Views/User.php:59
@@ -4453,152 +5125,261 @@ msgstr ""
msgid "This table shows the documentation pages."
msgstr ""
-#: IDF/Views/Wiki.php:61 IDF/Views/Wiki.php:106 IDF/Views/Wiki.php:147
+#: IDF/Views/Wiki.php:61 IDF/Views/Wiki.php:144 IDF/Views/Wiki.php:185
msgid "Page Title"
msgstr ""
-#: IDF/Views/Wiki.php:63 IDF/Views/Wiki.php:108 IDF/Views/Wiki.php:149
+#: IDF/Views/Wiki.php:63 IDF/Views/Wiki.php:103 IDF/Views/Wiki.php:146
+#: IDF/Views/Wiki.php:187
msgid "Updated"
msgstr ""
-#: IDF/Views/Wiki.php:67 IDF/Views/Wiki.php:153
+#: IDF/Views/Wiki.php:67 IDF/Views/Wiki.php:191
msgid "No documentation pages were found."
msgstr ""
-#: IDF/Views/Wiki.php:90
+#: IDF/Views/Wiki.php:88
+#, php-format
+msgid "%s Documentation Resources"
+msgstr ""
+
+#: IDF/Views/Wiki.php:94
+msgid "This table shows the resources that can be used on documentation pages."
+msgstr ""
+
+#: IDF/Views/Wiki.php:100
+msgid "Resource Title"
+msgstr ""
+
+#: IDF/Views/Wiki.php:107
+msgid "No resources were found."
+msgstr ""
+
+#: IDF/Views/Wiki.php:128
#, php-format
msgid "Documentation Search - %s"
msgstr ""
-#: IDF/Views/Wiki.php:101
+#: IDF/Views/Wiki.php:139
msgid "This table shows the pages found."
msgstr ""
-#: IDF/Views/Wiki.php:112
+#: IDF/Views/Wiki.php:150
msgid "No pages were found."
msgstr ""
-#: IDF/Views/Wiki.php:131
+#: IDF/Views/Wiki.php:169
#, php-format
msgid "%1$s Documentation Pages with Label %2$s"
msgstr ""
-#: IDF/Views/Wiki.php:141
+#: IDF/Views/Wiki.php:179
#, php-format
msgid "This table shows the documentation pages with label %s."
msgstr ""
-#: IDF/Views/Wiki.php:184
+#: IDF/Views/Wiki.php:222
#, php-format
-msgid "The page %s has been created."
+msgid "The page %2$s has been created."
msgstr ""
-#: IDF/Views/Wiki.php:271
+#: IDF/Views/Wiki.php:265
+#, php-format
+msgid "The resource %2$s has been created."
+msgstr ""
+
+#: IDF/Views/Wiki.php:409 IDF/Views/Wiki.php:448
msgid "The old revision has been deleted."
msgstr ""
-#: IDF/Views/Wiki.php:277
+#: IDF/Views/Wiki.php:415 IDF/Views/Wiki.php:454
#, php-format
msgid "Delete Old Revision of %s"
msgstr ""
-#: IDF/Views/Wiki.php:322
+#: IDF/Views/Wiki.php:496
#, php-format
-msgid "The page %s has been updated."
+msgid "The page %2$s has been updated."
msgstr ""
-#: IDF/Views/Wiki.php:360
+#: IDF/Views/Wiki.php:548
+#, php-format
+msgid "The resource %2$s has been updated."
+msgstr ""
+
+#: IDF/Views/Wiki.php:583
msgid "The documentation page has been deleted."
msgstr ""
-#: IDF/Views/Wiki.php:368
+#: IDF/Views/Wiki.php:591
#, php-format
msgid "Delete Page %s"
msgstr ""
-#: IDF/Views.php:126 IDF/Views.php:152
+#: IDF/Views/Wiki.php:623
+msgid "The documentation resource has been deleted."
+msgstr ""
+
+#: IDF/Views/Wiki.php:631
+#, php-format
+msgid "Delete Resource %s"
+msgstr ""
+
+#: IDF/Views.php:173 IDF/Views.php:199
msgid "Confirm Your Account Creation"
msgstr ""
-#: IDF/Views.php:172
+#: IDF/Views.php:219
msgid "Welcome! You can now participate in the life of your project of choice."
msgstr ""
-#: IDF/Views.php:198 IDF/Views.php:222 IDF/Views.php:263
+#: IDF/Views.php:245 IDF/Views.php:269 IDF/Views.php:310
msgid "Password Recovery"
msgstr ""
-#: IDF/Views.php:242
+#: IDF/Views.php:289
msgid ""
"Welcome back! Next time, you can use your broswer options to remember the "
"password."
msgstr ""
-#: IDF/Views.php:284
+#: IDF/Views.php:331
msgid "Here to Help You!"
msgstr ""
-#: IDF/Views.php:300
+#: IDF/Views.php:347
+msgid "InDefero Upload Archive Format"
+msgstr ""
+
+#: IDF/Views.php:363
msgid "InDefero API (Application Programming Interface)"
msgstr ""
-#: IDF/WikiPage.php:62
+#: IDF/Wiki/Page.php:62 IDF/Wiki/Resource.php:64
msgid "title"
msgstr ""
-#: IDF/WikiPage.php:63
+#: IDF/Wiki/Page.php:63
msgid ""
"The title of the page must only contain letters, digits or the dash "
"character. For example: My-new-Wiki-Page."
msgstr ""
-#: IDF/WikiPage.php:71
+#: IDF/Wiki/Page.php:71
msgid "A one line description of the page content."
msgstr ""
-#: IDF/WikiPage.php:196 IDF/WikiRevision.php:167
+#: IDF/Wiki/Page.php:196 IDF/Wiki/PageRevision.php:196
#, php-format
msgid "%2$s, %3$s"
msgstr ""
-#: IDF/WikiPage.php:198
+#: IDF/Wiki/Page.php:198
#, php-format
-msgid "Creation of page %s, by %s"
+msgid "Creation of page %2$s, by %3$s"
msgstr ""
-#: IDF/WikiPage.php:208
+#: IDF/Wiki/Page.php:208
#, php-format
-msgid "%s: Documentation page %s added - %s"
+msgid "%1$s: Documentation page %2$s added - %3$s"
msgstr ""
-#: IDF/WikiRevision.php:48
+#: IDF/Wiki/PageRevision.php:48
msgid "page"
msgstr ""
-#: IDF/WikiRevision.php:66
+#: IDF/Wiki/PageRevision.php:66 IDF/Wiki/ResourceRevision.php:64
msgid "A one line description of the changes."
msgstr ""
-#: IDF/WikiRevision.php:72
+#: IDF/Wiki/PageRevision.php:72
msgid "content"
msgstr ""
-#: IDF/WikiRevision.php:189
+#: IDF/Wiki/PageRevision.php:218 IDF/Wiki/ResourceRevision.php:311
#, php-format
-msgid "Change of %s, by %s"
+msgid "Change of %2$s, by %3$s"
msgstr ""
-#: IDF/WikiRevision.php:208
+#: IDF/Wiki/PageRevision.php:231
#, php-format
-msgid "%s: Documentation page %s updated - %s"
+msgid "%1$s: Documentation page %2$s updated - %3$s"
msgstr ""
-#: IDF/WikiRevision.php:262
+#: IDF/Wiki/PageRevision.php:293
#, php-format
-msgid "New Documentation Page %s - %s (%s)"
+msgid "New Documentation Page %1$s - %2$s (%3$s)"
msgstr ""
-#: IDF/WikiRevision.php:268
+#: IDF/Wiki/PageRevision.php:297
#, php-format
-msgid "Documentation Page Changed %s - %s (%s)"
+msgid "Documentation Page Changed %1$s - %2$s (%3$s)"
+msgstr ""
+
+#: IDF/Wiki/Resource.php:65
+msgid ""
+"The title of the resource must only contain letters, digits, dots or the "
+"dash character. For example: my-resource.png."
+msgstr ""
+
+#: IDF/Wiki/Resource.php:72
+msgid "MIME media type"
+msgstr ""
+
+#: IDF/Wiki/Resource.php:73
+msgid "The MIME media type of the resource."
+msgstr ""
+
+#: IDF/Wiki/Resource.php:81
+msgid "A one line description of the resource."
+msgstr ""
+
+#: IDF/Wiki/Resource.php:176 IDF/Wiki/ResourceRevision.php:308
+#, php-format
+msgid "%2$s, %3$s"
+msgstr ""
+
+#: IDF/Wiki/Resource.php:178
+#, php-format
+msgid "Creation of resource %2$s, by %3$s"
+msgstr ""
+
+#: IDF/Wiki/Resource.php:188
+#, php-format
+msgid "%1$s: Documentation resource %2$s added - %3$s"
+msgstr ""
+
+#: IDF/Wiki/ResourceRevision.php:47
+msgid "resource"
+msgstr ""
+
+#: IDF/Wiki/ResourceRevision.php:78
+msgid "File extension"
+msgstr ""
+
+#: IDF/Wiki/ResourceRevision.php:79
+msgid "The file extension of the uploaded resource."
+msgstr ""
+
+#: IDF/Wiki/ResourceRevision.php:94
+msgid "page usage"
+msgstr ""
+
+#: IDF/Wiki/ResourceRevision.php:116
+#, php-format
+msgid "id %d: %s"
+msgstr ""
+
+#: IDF/Wiki/ResourceRevision.php:263
+#, php-format
+msgid "Download (%s)"
+msgstr ""
+
+#: IDF/Wiki/ResourceRevision.php:270
+msgid "View resource details"
+msgstr ""
+
+#: IDF/Wiki/ResourceRevision.php:324
+#, php-format
+msgid "%1$s: Documentation resource %2$s updated - %3$s"
msgstr ""
diff --git a/src/IDF/relations.php b/src/IDF/relations.php
index 38f0ea1..b8ae4e3 100644
--- a/src/IDF/relations.php
+++ b/src/IDF/relations.php
@@ -22,7 +22,9 @@
# ***** END LICENSE BLOCK ***** */
$m = array();
-$m['IDF_Tag'] = array('relate_to' => array('IDF_Project'));
+$m['IDF_ProjectActivity'] = array('relate_to' => array('IDF_Project'));
+$m['IDF_Tag'] = array('relate_to' => array('IDF_Project'),
+ 'relate_to_many' => array('IDF_Project'));
$m['IDF_Issue'] = array('relate_to' => array('IDF_Project', 'Pluf_User', 'IDF_Tag'),
'relate_to_many' => array('IDF_Tag', 'Pluf_User'));
$m['IDF_IssueComment'] = array('relate_to' => array('IDF_Issue', 'Pluf_User'));
@@ -30,9 +32,12 @@ $m['IDF_IssueFile'] = array('relate_to' => array('IDF_IssueComment', 'Pluf_User'
$m['IDF_Upload'] = array('relate_to' => array('IDF_Project', 'Pluf_User'),
'relate_to_many' => array('IDF_Tag'));
$m['IDF_Search_Occ'] = array('relate_to' => array('IDF_Project'),);
-$m['IDF_WikiPage'] = array('relate_to' => array('IDF_Project', 'Pluf_User'),
- 'relate_to_many' => array('IDF_Tag', 'Pluf_User'));
-$m['IDF_WikiRevision'] = array('relate_to' => array('IDF_WikiPage', 'Pluf_User'));
+$m['IDF_Wiki_Page'] = array('relate_to' => array('IDF_Project', 'Pluf_User'),
+ 'relate_to_many' => array('IDF_Tag', 'Pluf_User'));
+$m['IDF_Wiki_PageRevision'] = array('relate_to' => array('IDF_Wiki_Page', 'Pluf_User'));
+$m['IDF_Wiki_Resource'] = array('relate_to' => array('IDF_Project', 'Pluf_User'));
+$m['IDF_Wiki_ResourceRevision'] = array('relate_to' => array('IDF_Wiki_Resource', 'Pluf_User'),
+ 'relate_to_many' => array('IDF_PageRevision', 'Pluf_User'));
$m['IDF_Review'] = array('relate_to' => array('IDF_Project', 'Pluf_User', 'IDF_Tag'),
'relate_to_many' => array('IDF_Tag', 'Pluf_User'));
$m['IDF_Review_Patch'] = array('relate_to' => array('IDF_Review', 'Pluf_User'));
diff --git a/src/IDF/templates/idf/admin/downloads.html b/src/IDF/templates/idf/admin/downloads.html
index c22be5e..a614484 100644
--- a/src/IDF/templates/idf/admin/downloads.html
+++ b/src/IDF/templates/idf/admin/downloads.html
@@ -1,5 +1,5 @@
{extends "idf/admin/base.html"}
-{block docclass}yui-t1{assign $inDownloads = true}{/block}
+{block docclass}yui-t3{assign $inDownloads = true}{/block}
{block body}
+{include 'idf/project/js-autocomplete.html'}{/block}
{/block}
{block context}
diff --git a/src/IDF/templates/idf/admin/tabs.html b/src/IDF/templates/idf/admin/tabs.html
index decea32..10ae8dc 100644
--- a/src/IDF/templates/idf/admin/tabs.html
+++ b/src/IDF/templates/idf/admin/tabs.html
@@ -10,11 +10,11 @@
{/if}
+{include 'idf/project/js-autocomplete.html'}{/block}
{/block}
+
{block context}
{trans 'No projects managed with InDefero were found.'}
-{if $isAdmin} -{aurl 'url', 'IDF_Views_Admin::projectCreate'} -{/if} -{else} -{foreach $projects as $p} - -- {$p} - {if $p.private} - {trans 'Private project'}{/if} -
-{$p.shortdesc}
-{trans 'Projects:'} | {$stats.projects} |
{trans 'Members:'} | {$stats.members} |
{trans 'Issues:'} | {$stats.issues} |
{trans 'Commits:'} | {$stats.commits} |
{trans 'Documentations:'} | {$stats.docpages} |
{trans 'Downloads:'} | {$stats.downloads} |
{trans 'Code reviews:'} | {$stats.reviews} |