39 Commits

Author SHA1 Message Date
Thomas Keller
6f4af6b68d Start 1.3.4 development 2012-11-18 23:58:18 +01:00
Thomas Keller
ebb8d46420 Release 1.3.3 2012-11-18 23:55:17 +01:00
Thomas Keller
6c5406dd99 Fix a problem in jquery.hotkeys that triggered global hotkeys when one was
in a password text field. Upstream should know of this problem for a long
time already, but hasn't released a fixed version yet, so we're applying
our own patch here (fixes issue 821).
2012-11-18 00:58:27 +01:00
Thomas Keller
4aa4100532 Update French translation from Transifex. 2012-11-18 00:28:30 +01:00
Thomas Keller
d90c1a2c23 $prj wasn't defined, so use the project reference that the page has instead (fixes issue 808) 2012-07-20 15:03:57 +02:00
Thomas Keller
22c1f92b2b Use git's "find copies harder" algorithm to - well - find copies in changesets
and render them as such.
2012-07-11 00:17:23 +02:00
Thomas Keller
d17098e703 Ensure that PHP doesn't interpret read ini file values and therefor
scrambles the output of hgrc files (issue 523).
2012-06-05 20:55:21 +02:00
Thomas Keller
64c6674762 Copy over all project properties, except a few scm settings and very
project-specific ones, when a new project is based on another one.
2012-05-21 23:33:38 +02:00
Thomas Keller
839444cc8a Use Pluf's new migration capabilities to prevent problems with the
circular dependency between project and project activity during
new db installations (issue 800).
ATTENTION: IDF now needs Pluf a45dc195 or newer!
2012-05-15 22:43:15 +02:00
Thomas Keller
831439120c Make the current_activity field in IDF_Project nullable and fix
a problem in the migration 25's down method (issue 800)
2012-05-15 22:38:27 +02:00
Thomas Keller
6bb886b92a If ssh public key data contain forward slashes, the SyncGit cron job
did not properly find and update the region which it should have
under its control (thanks to Simon Gareste for the fix!)
2012-05-14 19:38:07 +02:00
Thomas Keller
dd3474c06c Add two more targets to dump and restore application backups. 2012-05-12 02:25:33 +02:00
Thomas Keller
bcd515eed5 Do not display all project to a user if he has no rights for
_any_ project of the forge, but actually hide all... thanks
to René Klomp for this finding!
2012-05-11 23:26:42 +02:00
Thomas Keller
0826dab575 Start 1.3.3 development. 2012-05-09 22:10:24 +02:00
Thomas Keller
1c037f81a0 Release 1.3.2. 2012-05-09 22:09:13 +02:00
Thomas Keller
71c41fe940 Of course $ids should have been initialized beforehand... 2012-05-07 23:26:23 +02:00
Thomas Keller
8ad0707509 Fix the project display when no projects are available or visible. 2012-05-07 23:12:55 +02:00
Thomas Keller
a2d5b14a2c Start with 1.3.2 development. 2012-05-06 22:49:04 +02:00
Thomas Keller
16de6a0d77 Enter a release date and pin the current version. 2012-05-06 22:34:56 +02:00
Thomas Keller
03404adf64 - move getProjectsWithLabelCounts to IDF_Views (where the other functions
reside as well) and make it static
- refactor out the code from getProjects that determines which projects
  are visible by a user and use the same code to restrict the count that
  we calculate for all available project tags
- calculating the project stats is now no longer O(5n) but simply O(5)
  when it comes to SQL queries (where n is the number of filtered projects);
  remove the member statistic since it makes no sense in this context
2012-05-04 23:31:07 +02:00
Thomas Keller
dd2fa6f902 Remove OS9 line ending support again, this was left out for a reason.
Fix tests after issue 804 was fixed.
2012-05-04 01:01:33 +02:00
Thomas Keller
b6acf4c0e2 Replace the implementation of splitIntoLines by a new one that does
not need PHP's array_shift which tends to be very slow for arrays
with many thousand entries (fixes issue 804).
2012-05-04 00:48:53 +02:00
Thomas Keller
8db3c45763 Revamp this a little and make it jQuery 1.7 compatible (fixes issue 803) 2012-04-29 00:24:09 +02:00
Thomas Keller
e8882292b5 Improve the error we throw at the user if no configuration is found
to calculate the project activities.
2012-04-24 20:37:23 +02:00
Thomas Keller
bca3eb332e Reference the issue in which the Postgres issues have been tracked. 2012-04-22 23:11:48 +02:00
Thomas Keller
307c35ff42 Pulled updated French translation from Transifex (thanks to
Jonathan Aillet, again!)
2012-04-22 00:52:33 +02:00
Thomas Keller
786e9f81c0 Added Jonathan's email. 2012-04-21 19:03:25 +02:00
Thomas Keller
8cd19c0f53 Escape the xml file path arg. 2012-04-20 00:50:24 +02:00
Thomas Keller
d5394265ba Formatting fix. 2012-04-20 00:12:45 +02:00
Thomas Keller
0919cb83d8 Properly mark 1.3.1 dev version. 2012-04-19 23:40:50 +02:00
Thomas Keller
b7ad4bf47a Apparently the default project for tags is still 0, so make it explicit. 2012-04-19 00:37:09 +02:00
Thomas Keller
75f62663a9 Make the project field in the tags table nullable so it is (hopefully)
optional on setups with enabled foreign key constraints.
2012-04-19 00:14:10 +02:00
Thomas Keller
169fbe6216 Another Postgres issue fixed. 2012-04-18 23:22:32 +02:00
Thomas Keller
84d80af1ce Postgres seems to need every column in the group by, not only the PK. 2012-04-18 23:00:37 +02:00
Thomas Keller
d1542c9c00 Another Postgres issue (hopefully fixes issue 800). 2012-04-18 22:09:53 +02:00
Thomas Keller
4da01b2732 Another Postgres nuisance. 2012-04-18 22:05:17 +02:00
Thomas Keller
b44ad48fd5 Another PostgreSQL issue (hopefully) fixed. 2012-04-18 07:17:35 +02:00
Thomas Keller
3ae92627bc French translation pulled from transifex. 2012-04-18 00:59:41 +02:00
Thomas Keller
d46df5c129 Fix PostgreSQL compatibility issues. 2012-04-18 00:55:29 +02:00
28 changed files with 1580 additions and 570 deletions

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@
.settings
.tx/config
attachments
backups
indefero-*.zip
src/IDF/conf/idf.php
src/IDF/conf/idf.test.php

View File

@@ -7,6 +7,7 @@ Much appreciated contributors (in alphabetical order):
Andrew Nguyen <andrew-git-indefero@na-consulting.net>
Baptiste Durand-Bret <bathizte@ozazar.org>
Baptiste Michaud <bactisme@gmail.com> - Subversion sync
Benjamin Danon <benjamin@sphax3d.org> - French translation
Benjamin Jorand <benjamin.jorand@gmail.com> - Mercurial support
Brenda Wallace <shiny@cpan.org>
Brian Armstrong <brianar>
@@ -22,6 +23,7 @@ Much appreciated contributors (in alphabetical order):
Janez Troha <http://www.dz0ny.info> - Slovenian translation
Jean-Philippe Fleury <jpfleury>
Jerry <lxb429@gmail.com> - Chinese translation
Jonathan Aillet <jonathan.aillet@gmail.com> - French translation
Julien Issler <julien@issler.net>
Litew <litew9@gmail.com> - Russian translation
Ludovic Bellière <xrogaan>

View File

@@ -37,10 +37,11 @@ help:
@printf "\tpo-push - Send the all PO files to the transifex server.\n"
@printf "\tpo-pull - Get all PO files from the transifex server.\n"
@printf "\tpo-stats - Show translation statistics of all PO files.\n"
@printf "\nMisc Rules :\n";
@printf "\tdb-install - Install the database schema.\n"
@printf "\tdb-update - Update the database schema.\n"
@printf "\nRules for managing the database :\n";
@printf "\tdb-install - Install the database schema.\n"
@printf "\tdb-update - Update the database schema.\n"
@printf "\tdb-backup-foo - Create a named backup 'foo' with data from the current database.\n"
@printf "\tdb-restore-foo - Restore schema and the data from a named backup 'foo' to an empty database.\n"
#
# Internationalization rule, POT & PO file manipulation
@@ -139,8 +140,8 @@ po-stats:
# make develop_zipfile
#
%-zipfile:
@git archive --format=zip --prefix="indefero/" $(@:-zipfile=) \
> indefero-$(@:-zipfile=)-`git log $(@:-zipfile=) -n 1 \
@git archive --format=zip --prefix="indefero/" $* \
> indefero-$*-`git log $* -n 1 \
--pretty=format:%h`.zip
db-install:
@@ -148,3 +149,13 @@ db-install:
db-update:
@cd src && php "$(PLUF_PATH)/migrate.php" --conf=IDF/conf/idf.php -a -d
db-backup-%:
@[ -e backups ] || mkdir backups
@cd src && php "$(PLUF_PATH)/migrate.php" --conf=IDF/conf/idf.php -a -b ../backups $*
@echo Files for named backup $* have been saved into backups/ directory.
db-restore-%:
@cd src && php "$(PLUF_PATH)/migrate.php" --conf=IDF/conf/idf.php -a -r ../backups $*
@echo Files for named backup $* have been restored from the backups/ directory.

View File

@@ -1,4 +1,70 @@
# InDefero 1.3 - Sun Apr 15 21:10 2011 UTC
# InDefero 1.3.4 - xxx xxx xx xx:xx:xx UTC 201X
## Bugfixes
...
# InDefero 1.3.3 - Sun Nov 18 22:54:00 UTC 2012
**ATTENTION**: InDefero needs Pluf [a45dc195](http://projects.ceondo.com/p/pluf/source/commit/a45dc195)
or newer to run properly!
## Bugfixes
- A long standing bug in the Mercurial plugin that lead to corruption
of boolean configuration values in the `hgrc` of the served repository
has been fixed (issue 523).
- If an anonymous or authenticated user had no access to any project in a
forge, all projects were listed for him (but still no one was actually
accessible). This has been fixed.
- Fixed a problem where the SyncGit plugin doesn't properly updates the
authorized_keys file when the public key data contained slashes (thanks
to Simon Gareste for the fix!)
- Under PostgreSQL indefero could not be set up because of a circular
foreign key dependency. This has been fixed (issue 800).
- Under PostgreSQL new projects could not be created due to a failing
foreign key relation. Adding project tags was not possible for a similar
reason. This has been fixed (issue 800, continued).
- If a project was created based on the settings of an existing project,
not all settings, like for example the new notification settings, have
been copied. This has been changed insofar that now all properties except
the project's URL, logo and individual SCM settings are copied by default.
- Wiki pages couldn't be properly saved with E_NOTICE enabled because
of a syntax error (fixes issue 808).
- Indefero now shows detected copies in git changesets.
- A user is no longer redirected to the Help page if he enters 'H' in the
password text field on the login page (fixes issue 821).
# InDefero 1.3.2 - Wed May 09 20:05 2012 UTC
## Bugfixes
- Fix two bugs in the project list view if no project
is visible to the user or available in the forge (issue 805)
# InDefero 1.3.1 - Sun May 06 20:32 2012 UTC
## Bugfixes
- Compatiblity fixes for PostgreSQL (issue 800)
- Fix TOC generation in wiki (issue 803)
- Make the display of large files and diffs faster (issue 804)
- Make the project list faster and its tag list more accurate by not
counting projects that are invisible to the current user
## Language and Translations
- French translation updated (thanks to Jonathan Aillet!)
# InDefero 1.3 - Sun Apr 15 21:10 2012 UTC
This new major release of Indefero is possible thanks to the sponsor of
[Scilab Enterprises](http://www.scilab-enterprises.com/).
@@ -34,7 +100,7 @@ or newer to properly run this version of Indefero!
emails for one object are uniquely identifyable to support a grouped view
in email clients that support that. (fixes issues 334, 452, 480, and 791)
- Indefero can now be configured to record activity metrics for all projects
in a forge. This needs a special cron job named 'activitycron.php`
in a forge. This needs a special cron job named `activitycron.php`
(under `scripts`) that is run on a regular basis. The metrics can be
fine-tuned via `activity_section_weights` and `activity_lookback` in
`idf.php` and the result is visible as green bar in the project list view.

View File

@@ -2,7 +2,7 @@
<?php
$xmlfile = dirname(__FILE__) .'/test/report.xml';
passthru('phpunit --coverage-clover='.$xmlfile);
passthru('phpunit --coverage-clover='.escapeshellarg($xmlfile));
$xml = simplexml_load_string(file_get_contents($xmlfile));
unlink($xmlfile);
printf(

View File

@@ -44,10 +44,15 @@ class IDF_ActivityTaxonomy
{
public static function recalculateTaxnomies(DateTime $date)
{
$sectionWeights = Pluf::f('activity_section_weights', null);
$lookback = Pluf::f('activity_lookback', null);
if ($sectionWeights === null || $lookback === null) {
throw new LogicException('activity configuration is missing in idf.php');
}
//
// query and normalize the section weights
//
$sectionWeights = Pluf::f('activity_section_weights', array());
$allWeights = array_sum($sectionWeights);
if ($allWeights == 0) {
throw new LogicException('the sum of all "activity_section_weights" must not be 0');
@@ -59,7 +64,6 @@ class IDF_ActivityTaxonomy
//
// determine the date boundaries
//
$lookback = Pluf::f('activity_lookback', 0);
if ($lookback < 1) {
throw new LogicException('lookback must be greater or equal to 1');
}
@@ -141,7 +145,12 @@ class IDF_ActivityTaxonomy
$cache[$argIdent] = 0;
list($higher, $lower) = $dateBoundaries;
$sql = new Pluf_SQL('model_class IN ("'.implode('","', $classes).'") '.
$db = Pluf::db();
$classes_esc = array();
foreach ($classes as $class) {
$classes_esc[] = $db->esc($class);
}
$sql = new Pluf_SQL('model_class IN ('.implode(',', $classes_esc).') '.
'AND creation_dtime >= %s AND creation_dtime <= %s',
array($lower, $higher));

View File

@@ -84,7 +84,7 @@ class IDF_Conf extends Pluf_Model
function initCache()
{
$this->datacache = new ArrayObject();
$this->datacache = array();
$sql = new Pluf_SQL('project=%s', $this->_project->id);
foreach ($this->getList(array('filter' => $sql->gen())) as $val) {
$this->datacache[$val->vkey] = $val->vdesc;
@@ -129,4 +129,12 @@ class IDF_Conf extends Pluf_Model
$this->initCache();
}
}
function getKeys()
{
if ($this->datacache === null) {
$this->initCache();
}
return array_keys($this->datacache);
}
}

View File

@@ -147,7 +147,7 @@ class IDF_FileUtil
* Splits a string into separate lines while retaining the individual
* line ending character for every line.
*
* OS9 line endings are not supported.
* OS 9 line endings are not supported.
*
* @param string content
* @param boolean if true, skip completely empty lines
@@ -155,19 +155,16 @@ class IDF_FileUtil
*/
public static function splitIntoLines($content, $skipEmpty = false)
{
$flags = PREG_SPLIT_OFFSET_CAPTURE;
if ($skipEmpty) $flags |= PREG_SPLIT_NO_EMPTY;
$splitted = preg_split("/\r\n|\n/", $content, -1, $flags);
$last_off = -1;
$last_off = 0;
$lines = array();
while (($split = array_shift($splitted)) !== null) {
if ($last_off != -1) {
$lines[] .= substr($content, $last_off, $split[1] - $last_off);
}
$last_off = $split[1];
while (preg_match("/\r\n|\n/", $content, $m, PREG_OFFSET_CAPTURE, $last_off)) {
$next_off = strlen($m[0][0]) + $m[0][1];
$line = substr($content, $last_off, $next_off - $last_off);
$last_off = $next_off;
if ($line !== $m[0][0] || !$skipEmpty) $lines[] = $line;
}
$lines[] = substr($content, $last_off);
$line = substr($content, $last_off);
if ($line !== false && strlen($line) > 0) $lines[] = $line;
return $lines;
}

View File

@@ -52,31 +52,6 @@ class IDF_Forge
$this->conf->setVal('project_labels', $labels);
}
public function getProjectLabelsWithCounts() {
$sql = new Pluf_SQL('project=0');
$tagList = Pluf::factory('IDF_Tag')->getList(array(
'filter' => $sql->gen(),
'view' => 'join_projects',
'order' => 'class ASC, lcname ASC'
));
$maxProjectCount = 0;
foreach ($tagList as $tag) {
$maxProjectCount = max($maxProjectCount, $tag->project_count);
}
$tags = array();
foreach ($tagList as $tag) {
// group by class
if (!array_key_exists($tag->class, $tags)) {
$tags[$tag->class] = array();
}
$tag->rel_project_count = $tag->project_count / (double) $maxProjectCount;
$tags[$tag->class][] = $tag;
}
return $tags;
}
public function setCustomForgePageEnabled($enabled) {
$this->conf->setVal('custom_forge_page_enabled', $enabled);
}

View File

@@ -360,45 +360,35 @@ class IDF_Form_Admin_ProjectCreate extends Pluf_Form
$conf = new IDF_Conf();
$conf->setProject($project);
$keys = array('scm', 'svn_remote_url', 'svn_username',
'svn_password', 'mtn_master_branch', 'external_project_url');
foreach ($keys as $key) {
$this->cleaned_data[$key] = (!empty($this->cleaned_data[$key])) ?
$this->cleaned_data[$key] : '';
$conf->setVal($key, $this->cleaned_data[$key]);
}
if ($this->cleaned_data['template'] != '--') {
$tmplconf = new IDF_Conf();
$tmplconf->setProject($tmpl);
// We need to get all the configuration variables we want from
// the old project and put them into the new project.
$props = array(
'labels_download_predefined' => IDF_Form_UploadConf::init_predefined,
'labels_download_one_max' => IDF_Form_UploadConf::init_one_max,
'labels_wiki_predefined' => IDF_Form_WikiConf::init_predefined,
'labels_wiki_one_max' => IDF_Form_WikiConf::init_one_max,
'labels_issue_template' => IDF_Form_IssueTrackingConf::init_template,
'labels_issue_open' => IDF_Form_IssueTrackingConf::init_open,
'labels_issue_closed' => IDF_Form_IssueTrackingConf::init_closed,
'labels_issue_predefined' => IDF_Form_IssueTrackingConf::init_predefined,
'labels_issue_one_max' => IDF_Form_IssueTrackingConf::init_one_max,
'issue_relations' => IDF_Form_IssueTrackingConf::init_relations,
'webhook_url' => '',
'downloads_access_rights' => 'all',
'review_access_rights' => 'all',
'wiki_access_rights' => 'all',
'source_access_rights' => 'all',
'issues_access_rights' => 'all',
'downloads_notification_email' => '',
'review_notification_email' => '',
'wiki_notification_email' => '',
'source_notification_email' => '',
'issues_notification_email' => '',
);
foreach ($props as $prop => $def) {
$conf->setVal($prop, $tmplconf->getVal($prop, $def));
$allKeys = $tmplconf->getKeys();
$scm = $this->cleaned_data['scm'];
$ignoreKeys = array('scm', 'external_project_url', 'logo');
// copy over all existing variables, except scm-related data and
// the project url / logo
foreach ($allKeys as $key) {
if (in_array($key, $ignoreKeys) || strpos($key, $scm.'_') === 0) {
continue;
}
$conf->setVal($key, $tmplconf->getVal($key));
}
}
$keys = array(
'scm', 'svn_remote_url', 'svn_username',
'svn_password', 'mtn_master_branch',
'external_project_url'
);
foreach ($keys as $key) {
$this->cleaned_data[$key] = !empty($this->cleaned_data[$key]) ?
$this->cleaned_data[$key] : '';
$conf->setVal($key, $this->cleaned_data[$key]);
}
$project->created();
if ($this->cleaned_data['template'] == '--') {

View File

@@ -0,0 +1,47 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of InDefero, an open source project management application.
# Copyright (C) 2008-2011 Céondo Ltd and contributors.
#
# InDefero is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# InDefero is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
function IDF_Migrations_25NullableProjectInTag_up($params=null)
{
$engine = Pluf::f('db_engine');
$db = Pluf::db();
if ($engine === 'PostgreSQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_tags ALTER COLUMN project DROP NOT NULL');
} else if ($engine === 'MySQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_tags MODIFY project MEDIUMINT NULL');
// this is only needed for non-transactional setups where MySQL set 0 as default value
$db->execute('UPDATE '.$db->pfx.'idf_tags SET project=NULL WHERE project=0');
}
}
function IDF_Migrations_25NullableProjectInTag_down($params=null)
{
$engine = Pluf::f('db_engine');
$db = Pluf::db();
if ($engine === 'PostgreSQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_tags ALTER COLUMN project SET NOT NULL');
} else if ($engine === 'MySQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_tags MODIFY project MEDIUMINT NOT NULL');
}
}

View File

@@ -0,0 +1,46 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of InDefero, an open source project management application.
# Copyright (C) 2008-2012 Céondo Ltd and contributors.
#
# InDefero is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# InDefero is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
function IDF_Migrations_26NullableActivityInProject_up($params=null)
{
$engine = Pluf::f('db_engine');
$db = Pluf::db();
if ($engine === 'PostgreSQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_projects ALTER COLUMN current_activity DROP NOT NULL');
} else if ($engine === 'MySQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_projects MODIFY current_activity MEDIUMINT NULL');
// this is only needed for non-transactional setups where MySQL set 0 as default value
$db->execute('UPDATE '.$db->pfx.'idf_projects SET current_activity=NULL WHERE current_activity=0');
}
}
function IDF_Migrations_26NullableActivityInProject_down($params=null)
{
$engine = Pluf::f('db_engine');
$db = Pluf::db();
if ($engine === 'PostgreSQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_projects ALTER COLUMN current_activity SET NOT NULL');
} else if ($engine === 'MySQL') {
$db->execute('ALTER TABLE '.$db->pfx.'idf_projects MODIFY current_activity MEDIUMINT NOT NULL');
}
}

View File

@@ -119,5 +119,9 @@ function IDF_Migrations_Backup_restore($folder, $name)
foreach ($full_data as $model => $data) {
Pluf_Test_Fixture::load($data, false);
}
foreach ($models as $model) {
$schema->model = new $model();
$schema->createConstraints();
}
return true;
}

View File

@@ -62,6 +62,10 @@ function IDF_Migrations_Install_setup($params=null)
$schema->model = new $model();
$schema->createTables();
}
foreach ($models as $model) {
$schema->model = new $model();
$schema->createConstraints();
}
// Install the permissions
$perm = new Pluf_Permission();
$perm->name = 'Project membership';
@@ -120,6 +124,10 @@ function IDF_Migrations_Install_teardown($params=null)
);
$db = Pluf::db();
$schema = new Pluf_DB_Schema($db);
foreach ($models as $model) {
$schema->model = new $model();
$schema->dropConstraints();
}
foreach ($models as $model) {
$schema->model = new $model();
$schema->dropTables();

View File

@@ -64,7 +64,7 @@ class IDF_Plugin_SyncGit_Cron
// We update only the part of the file between IDF_START / IDF_END comment
$original_keys = file_get_contents($authorized_keys);
if (strstr($original_keys, "# indefero start") && strstr($original_keys, "# indefero end")) {
$out = preg_replace('/(#\sindefero\sstart).+(#\sindefero\send\s\s?)/isU',
$out = preg_replace('%(#\sindefero\sstart).+(#\sindefero\send\s\s?)%isU',
$out, $original_keys);
} else {
$out .= $original_keys;

View File

@@ -178,7 +178,10 @@ class IDF_Plugin_SyncMercurial
// Generate hgrc content
if (is_file($hgrc_file)) {
$tmp_content = parse_ini_file($hgrc_file, true);
$tmp_content = @parse_ini_file($hgrc_file, true, INI_SCANNER_RAW);
if ($tmp_content === false) {
throw new Exception('could not parse "'.$hgrc_file.'" because of syntax problems');
}
$tmp_content['web']['allow_push'] = $allow_push;
}
else {

View File

@@ -105,6 +105,8 @@ class IDF_Project extends Pluf_Model
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_ProjectActivity',
'blank' => true,
'is_null' => true,
'default' => null,
'verbose' => __('current project activity'),
),
);
@@ -115,8 +117,7 @@ class IDF_Project extends Pluf_Model
array(
'join' => 'LEFT JOIN '.$activityTable.' ON current_activity='.$activityTable.'.id '
.'LEFT JOIN '.$tagTable.' ON idf_project_id='.$this->getSqlTable().'.id',
'select' => $this->getSelect().', date, value',
'group' => $this->getSqlTable().'.id',
'select' => 'DISTINCT '.$this->getSelect().', date, value',
'props' => array(
'date' => 'current_activity_date',
'value' => 'current_activity_value'

View File

@@ -52,11 +52,11 @@ class IDF_Scm_Git extends IDF_Scm
* A doc/Guide utilisateur/images/ftp-nautilus.png
* M doc/Guide utilisateur/textes/log_boot_PEGASE.txt
*
* Status letters mean : Added (A), Deleted (D), Modified (M), Renamed (R)
* Status letters mean : Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R)
*/
public function getChanges($commit)
{
$cmd = sprintf('GIT_DIR=%s '.Pluf::f('git_path', 'git').' show %s --name-status --pretty="format:" --diff-filter="[A|D|M|R]" -M',
$cmd = sprintf('GIT_DIR=%s '.Pluf::f('git_path', 'git').' show %s --name-status --pretty="format:" --diff-filter="[A|C|D|M|R]" -C -C',
escapeshellarg($this->repo),
escapeshellarg($commit));
$out = array();
@@ -89,6 +89,9 @@ class IDF_Scm_Git extends IDF_Scm
} else if ($action == 'R') {
$matches = preg_split("/\t/", $line);
$return->renames[$matches[1]] = $matches[2];
} else if ($action == 'C') {
$matches = preg_split("/\t/", $line);
$return->copies[$matches[1]] = $matches[2];
}
}
}

View File

@@ -48,7 +48,9 @@ class IDF_Tag extends Pluf_Model
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Project',
'blank' => false,
'blank' => true,
'is_null' => true,
'default' => null,
'verbose' => __('project'),
),
'class' =>
@@ -76,13 +78,14 @@ class IDF_Tag extends Pluf_Model
);
$table = $this->_con->pfx.'idf_project_idf_tag_assoc';
$cols = implode(', ', array_keys($this->_a['cols']));
$this->_a['views'] = array(
'join_projects' =>
array(
'join' => 'LEFT JOIN '.$table
.' ON idf_tag_id=id',
'select' => $this->getSelect().',COUNT(idf_project_id) as project_count',
'group' => 'idf_tag_id',
'group' => $cols,
'props' => array('project_count' => 'project_count'),
),
);
@@ -146,7 +149,7 @@ class IDF_Tag extends Pluf_Model
$class = trim($class);
$name = trim($name);
$gtag = new IDF_Tag();
$sql = new Pluf_SQL('class=%s AND lcname=%s AND project=0',
$sql = new Pluf_SQL('class=%s AND lcname=%s AND project IS NULL',
array($class, mb_strtolower($name)));
$tags = $gtag->getList(array('filter' => $sql->gen()));
if ($tags->count() < 1) {
@@ -154,6 +157,7 @@ class IDF_Tag extends Pluf_Model
$tag = new IDF_Tag();
$tag->name = $name;
$tag->class = $class;
$tag->project = null;
$tag->create();
return $tag;
}

View File

@@ -83,7 +83,7 @@ class IDF_Template_MarkdownForge extends Pluf_Template_Tag
$name = $class;
$class = IDF_TAG_DEFAULT_CLASS;
}
$sql = new Pluf_SQL('class=%s AND lcname=%s AND project=0',
$sql = new Pluf_SQL('class=%s AND lcname=%s AND project IS NULL',
array(strtolower($class), mb_strtolower($name)));
$tag = Pluf::factory('IDF_Tag')->getOne(array('filter' => $sql->gen()));
}

View File

@@ -85,7 +85,7 @@ class IDF_Views
$projects = self::getProjects($request->user, $tag, $order);
$stats = self::getProjectsStatistics($projects);
$projectLabels = IDF_Forge::instance()->getProjectLabelsWithCounts();
$projectLabels = self::getProjectLabelsWithCounts($request->user);
return Pluf_Shortcuts_RenderToResponse('idf/listProjects.html',
array('page_title' => __('Projects'),
@@ -371,6 +371,62 @@ class IDF_Views
}
/**
* Returns a list of ids of projects that are visible for the given user
*
* @param Pluf_User $user
*/
private static function getUserVisibleProjectIds($user)
{
$db =& Pluf::db();
// the administrator can see all projects
if ($user->administrator) {
$ids = array();
$sql_results = $db->select(
'SELECT id FROM '.Pluf::f('db_table_prefix', '').'idf_projects'
);
foreach ($sql_results as $id) {
$ids[] = $id['id'];
}
return $ids;
}
// anonymous users can only see non-private projects
$false = Pluf_DB_BooleanToDb(false, $db);
$sql_results = $db->select(
'SELECT id FROM '.$db->pfx.'idf_projects '.
'WHERE '.$db->qn('private').'='.$false
);
$ids = array();
foreach ($sql_results as $id) {
$ids[] = $id['id'];
}
// registered users may additionally see private projects with which
// they're somehow affiliated
if (!$user->isAnonymous()) {
$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()));
if ($rows->count() > 0) {
foreach ($rows as $row) {
if (in_array($row->model_id, $ids))
continue;
$ids[] = $row->model_id;
}
}
}
return $ids;
}
/**
* Returns a list of projects accessible for the user and optionally filtered by tag.
*
@@ -381,39 +437,18 @@ class IDF_Views
public static function getProjects($user, $tag = false, $order = 'name')
{
$db =& Pluf::db();
$false = Pluf_DB_BooleanToDb(false, $db);
$sql = new Pluf_SQL(1);
$sql = new Pluf_SQL('1=1');
if ($tag !== false) {
$sql->SAnd(new Pluf_SQL('idf_tag_id=%s', $tag->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->SAnd($authSql);
$projectIds = self::getUserVisibleProjectIds($user);
if (count($projectIds) == 0) {
return new ArrayObject();
}
$sql->SAnd(new Pluf_SQL(sprintf($db->pfx.'idf_projects.id IN (%s)', implode(', ', $projectIds))));
$orderTypes = array(
'name' => 'name ASC',
'activity' => 'value DESC, name ASC',
@@ -425,6 +460,48 @@ class IDF_Views
));
}
/**
* Returns a list of global tags each carrying the number of projects that have the
* particular tag set
*
* @param Pluf_User $user
* @return array
*/
public static function getProjectLabelsWithCounts($user) {
$sql = new Pluf_SQL('project IS NULL');
$projectIds = self::getUserVisibleProjectIds($user);
if (count($projectIds) == 0) {
return new ArrayObject();
}
$sql->SAnd(new Pluf_SQL(sprintf('idf_project_id IN (%s)', implode(', ', $projectIds))));
$tagList = Pluf::factory('IDF_Tag')->getList(array(
'filter' => $sql->gen(),
'view' => 'join_projects',
'order' => 'class ASC, lcname ASC'
));
$maxProjectCount = 0;
foreach ($tagList as $tag) {
$maxProjectCount = max($maxProjectCount, $tag->project_count);
}
$tags = array();
foreach ($tagList as $tag) {
// group by class
if (!array_key_exists($tag->class, $tags)) {
$tags[$tag->class] = array();
}
$tag->rel_project_count = $tag->project_count / (double) $maxProjectCount;
$tags[$tag->class][] = $tag;
}
return $tags;
}
/**
* Returns statistics on a list of projects.
*
@@ -433,27 +510,30 @@ class IDF_Views
*/
public static function getProjectsStatistics($projects)
{
// Init the return var
$forgestats = array('downloads' => 0,
'reviews' => 0,
'issues' => 0,
'docpages' => 0,
'commits' => 0);
// Count for each projects
foreach ($projects as $p) {
$pstats = $p->getStats();
$forgestats['downloads'] += $pstats['downloads'];
$forgestats['reviews'] += $pstats['reviews'];
$forgestats['issues'] += $pstats['issues'];
$forgestats['docpages'] += $pstats['docpages'];
$forgestats['commits'] += $pstats['commits'];
$projectIds = array(0);
foreach ($projects as $project) {
$projectIds[] = $project->id;
}
// Count members
$sql = new Pluf_SQL('first_name != %s', array('---'));
$forgestats['members'] = Pluf::factory('Pluf_User')
->getCount(array('filter' => $sql->gen()));
$forgestats = array();
// count overall project stats
$forgestats['total'] = 0;
$what = array(
'downloads' => 'IDF_Upload',
'reviews' => 'IDF_Review',
'issues' => 'IDF_Issue',
'docpages' => 'IDF_Wiki_Page',
'commits' => 'IDF_Commit',
);
foreach ($what as $key => $model) {
$count = Pluf::factory($model)->getCount(array(
'filter' => sprintf('project IN (%s)', implode(', ', $projectIds))
));
$forgestats[$key] = $count;
$forgestats['total'] += $count;
}
return $forgestats;
}

View File

@@ -167,7 +167,7 @@ class IDF_Wiki_PageRevision extends Pluf_Model
if (count($matches) > 1 && count($matches[1]) > 0) {
foreach ($matches[1] as $resourceName) {
$sql = new Pluf_SQL('project=%s AND title=%s',
array($prj->id, $resourceName));
array($page->get_project()->id, $resourceName));
$resources = Pluf::factory('IDF_Wiki_Resource')->getList(array('filter'=>$sql->gen()));
if ($resources->count() == 0)
continue;

File diff suppressed because it is too large Load Diff

View File

@@ -48,7 +48,6 @@
<strong>{trans 'Filtered project stats'}</strong>
<dl class="statistics smaller">
<dt>{trans 'Members:'}</dt><dd>{$stats.members}</dd>
<dt>{trans 'Issues:'}</dt><dd>{$stats.issues}</dd>
<dt>{trans 'Commits:'}</dt><dd>{$stats.commits}</dd>
<dt>{trans 'Documentations:'}</dt><dd>{$stats.docpages}</dd>

View File

@@ -1,5 +1,5 @@
<?php
return array(
'version' => '1.3-dev',
'version' => '1.3.4-dev',
'revision' => '$Format:%H$',
);

View File

@@ -80,7 +80,6 @@
0 => '',
1 => 11,
2 => '
',
),
),

View File

@@ -44,7 +44,7 @@
handleObj.handler = function( event ) {
// Don't fire in text-accepting inputs that we didn't directly bind to
if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
if ( this !== event.target && (/textarea|select|input/i.test( event.target.nodeName ) ||
event.target.type === "text" || $(event.target).prop('contenteditable') == 'true' )) {
return;
}

View File

@@ -1,9 +1,12 @@
$(document).ready(function() {
$(":header", "#wiki-content").map(function(index) {
this.id = "wikititle_" + index;
$("<a href='#" + this.id + "'>" + jQuery.fn.text([this]) + "</a>")
.addClass("wiki-" + this.tagName.toLowerCase())
.appendTo('#wiki-toc-content');
var $header = $(this);
var $toc = $('#wiki-toc-content');
$header.attr('id', 'wikititle_' + index);
$('<a />').attr('href', '#' + $header.attr('id'))
.text($header.text())
.addClass("wiki-" + $header[0].tagName.toLowerCase())
.appendTo($toc);
});
if ($('#wiki-toc-content *').size() < 2)
$('#wiki-toc').hide();