Compare commits
185 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d7843a55bd | ||
|
b7833b5d23 | ||
|
0f617f8e09 | ||
|
fbc1fab68d | ||
|
68890c3c48 | ||
|
10f08386f7 | ||
|
45fa309c07 | ||
|
2ad13a96f9 | ||
|
73f95de843 | ||
|
c13d1aba30 | ||
|
42f561dc75 | ||
|
8280add935 | ||
|
bbc29c889f | ||
|
e5ee6d8fca | ||
|
738a8bdd60 | ||
|
119faf55cf | ||
|
7b0ece42f0 | ||
|
3c29e4e6ae | ||
|
a5f97c59d9 | ||
|
77c7f8ecfe | ||
|
dc34829afe | ||
|
10245113d5 | ||
|
349970cfaf | ||
|
0056e3f0b2 | ||
|
4e7d3618a7 | ||
|
548a427148 | ||
|
49e5aa783d | ||
|
b9d8eeea9e | ||
|
75777daf4b | ||
|
d3b76975cd | ||
|
64fb5b3bf0 | ||
|
51842c02f6 | ||
|
cc6f1c7cd8 | ||
|
5d24931d9b | ||
|
e2bce19526 | ||
|
9653f1a341 | ||
|
a5a5c7b2b6 | ||
|
c486ca928b | ||
|
3a28fe9d28 | ||
|
8da6fe7287 | ||
|
52be41186f | ||
|
96e8f4ae3c | ||
|
355f9ca05f | ||
|
ef40b0a34e | ||
|
73f6430a60 | ||
|
2b107c1610 | ||
|
93d379f293 | ||
|
6d415e9ec5 | ||
|
577aac2069 | ||
|
73641a03d5 | ||
|
0b580ba2ec | ||
|
a8a292a3c5 | ||
|
ec1d21a625 | ||
|
078c6feae8 | ||
|
63aedd6b42 | ||
|
1e3dfef438 | ||
|
c72e9f4eb0 | ||
|
857c11933a | ||
|
30a3515e94 | ||
|
ff4f8afde8 | ||
|
8050463a12 | ||
|
73dba2fa1a | ||
|
3c46b7734f | ||
|
48ff314487 | ||
|
4fa7a20fd3 | ||
|
75280d6892 | ||
|
6c5fde77b4 | ||
|
646cf6479b | ||
|
1d24432f8d | ||
|
37aa3d8b69 | ||
|
9437a19ee0 | ||
|
6c04fa80bd | ||
|
a667227943 | ||
|
8d32905913 | ||
|
58ab16432c | ||
|
aa383ffb1b | ||
|
f3cadfe013 | ||
|
c7aa91fc29 | ||
|
e5934e0a3a | ||
|
b6c5e803cb | ||
|
ec8ff4f76b | ||
|
06668db697 | ||
|
cab5d35771 | ||
|
a82b4b7b6b | ||
|
37e0604647 | ||
|
4765ca2232 | ||
|
6edaf03faa | ||
|
0dedee4429 | ||
|
078c75514e | ||
|
838645463d | ||
|
157819195b | ||
|
25d7a5a776 | ||
|
9d9541ee11 | ||
|
c1e23ae9e2 | ||
|
14e074b122 | ||
|
c3ae1970ca | ||
|
fbcdacdccf | ||
|
f473691479 | ||
|
f7a7ac39f3 | ||
|
ca5270a074 | ||
|
0e421c0b34 | ||
|
cb375dea26 | ||
|
6845f59150 | ||
|
021805f1e1 | ||
|
95881bd7f1 | ||
|
3c59c80bcc | ||
|
b3bacf25ff | ||
|
99992442f5 | ||
|
dd56d681b3 | ||
|
ba18f30c4f | ||
|
82e2684004 | ||
|
dc6f25cdef | ||
|
36c1f98438 | ||
|
ac7be1bde2 | ||
|
1a067ca107 | ||
|
c321e4828b | ||
|
68cc1ed5d3 | ||
|
69a7a58ce7 | ||
|
c0dfd6b5dc | ||
|
7d6cb22291 | ||
|
32507085b4 | ||
|
c488278ce1 | ||
|
ad17d797b2 | ||
|
2b1a741946 | ||
|
cbae598893 | ||
|
d153cd9049 | ||
|
2a15e2a350 | ||
|
1815aaa909 | ||
|
bdea6e4cbb | ||
|
75af09062f | ||
|
c366124917 | ||
|
16ce0da5f9 | ||
|
2ab52e7eaf | ||
|
fcefbe719f | ||
|
7d3f7e226c | ||
|
3848bd8d22 | ||
|
0873d44162 | ||
|
6cf4f00f92 | ||
|
d6c0b7a680 | ||
|
25e296fbb6 | ||
|
e235242ea6 | ||
|
9b39d63104 | ||
|
8915b45948 | ||
|
29e053bf6b | ||
|
a15107558c | ||
|
b320375d60 | ||
|
fb66e1e98f | ||
|
2f0156e63b | ||
|
e31d822d74 | ||
|
15cba014ba | ||
|
88a1bf9c94 | ||
|
d014b36ee2 | ||
|
cefdceba13 | ||
|
1c8490be6b | ||
|
1243a8f6ad | ||
|
d98dda645e | ||
|
44ea8f1817 | ||
|
6ef721d3a8 | ||
|
7d84da4d7c | ||
|
a53c6a1778 | ||
|
b75286375e | ||
|
ad8a6d3071 | ||
|
54b37ac5b6 | ||
|
bc434504b1 | ||
|
88ce10b8e6 | ||
|
0abb706ded | ||
|
54abd7bc7b | ||
|
c866d09e27 | ||
|
668b49df40 | ||
|
3476541bf4 | ||
|
2c9cf96245 | ||
|
39699ba723 | ||
|
0fd0c40e89 | ||
|
d31cd2aef4 | ||
|
c83e2e6f30 | ||
|
f55769a946 | ||
|
8345a02aaa | ||
|
1c51437569 | ||
|
63cdede854 | ||
|
d216e21858 | ||
|
358a774017 | ||
|
3c162486e4 | ||
|
a3f40447c0 | ||
|
96784b6e7c | ||
|
37cb05ff38 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ www/test.php
|
||||
www/media/upload
|
||||
src/IDF/gettexttemplates
|
||||
indefero-*.zip
|
||||
src/IDF/conf/path.php
|
||||
|
15
AUTHORS
15
AUTHORS
@@ -10,9 +10,20 @@ Much appreciated contributors:
|
||||
Julien Issler
|
||||
Manuel Eidenberger <eidenberger@gmail.com>
|
||||
Ciaran Gultnieks
|
||||
Mehdi Kabab
|
||||
Mehdi Kabab <http://pioupioum.fr/>
|
||||
Sindre R. Myren
|
||||
Patrick Georgi <patrick.georgi@coresystems.de>
|
||||
Adrien Bustany
|
||||
Charles Melbye
|
||||
Baptiste Durand-Bret
|
||||
Andrew Nguyen
|
||||
David Feeney
|
||||
Denis Kot <denis.kot@gmail.com>
|
||||
Samuel Suther
|
||||
Ludovic Bellière
|
||||
Brian Armstrong
|
||||
Raphaël Emourgeon
|
||||
|
||||
And all the nice users who spent time reporting issues and promoting
|
||||
the project. The project could not live without them.
|
||||
the project. The project could not live without them.
|
||||
|
||||
|
@@ -59,6 +59,8 @@ Here is the step-by-step installation procedure:
|
||||
* The InDefero installation folder is the folder containing this file INSTALL.mdtext.
|
||||
* Make a copy of `src/IDF/conf/idf.php-dist` as `src/IDF/conf/idf.php`.
|
||||
* Update the idf.php file to match your system.
|
||||
* Make a copy of `src/IDF/conf/path.php-dist` as `src/IDF/conf/path.php`.
|
||||
* Update the path.php file to match your installation paths. It should work out of the box if you followed the recommended file layout.
|
||||
* Open a terminal/shell and go into the `src` folder in the InDefero installation folder.
|
||||
|
||||
**Command:**
|
||||
@@ -73,8 +75,7 @@ Here is the step-by-step installation procedure:
|
||||
**Bootstrap script:**
|
||||
|
||||
<?php
|
||||
set_include_path(get_include_path().PATH_SEPARATOR.'/home/www/indefero/src');
|
||||
set_include_path(get_include_path().PATH_SEPARATOR.'/home/www/pluf/src');
|
||||
require '/home/www/indefero/src/IDF/conf/path.php';
|
||||
require 'Pluf.php';
|
||||
Pluf::start('/home/www/indefero/src/IDF/conf/idf.php');
|
||||
Pluf_Dispatcher::loadControllers(Pluf::f('idf_views'));
|
||||
@@ -97,7 +98,7 @@ Here is the step-by-step installation procedure:
|
||||
* Open the `www/index.php` file and ensure that the path to Pluf and
|
||||
Indefero are correctly set for your configuration.
|
||||
* Now you can login with this user into the interface.
|
||||
* Click on the Administer link on top and create your first project.
|
||||
* Click on the Forge Management link on top and create your first project.
|
||||
|
||||
## Upgrade InDefero
|
||||
|
||||
@@ -112,11 +113,11 @@ To upgrade:
|
||||
|
||||
**Upgrade commands:**
|
||||
|
||||
$ cd /home/www/indefero/src
|
||||
$ php /home/www/pluf/src/migrate.php --conf=IDF/conf/idf.php -a -d -u
|
||||
$ php /home/www/pluf/src/migrate.php --conf=IDF/conf/idf.php -a -d
|
||||
|
||||
|
||||
|
||||
## Repository Synchronization
|
||||
|
||||
The documentation is available in the `doc` folder.
|
||||
@@ -162,6 +163,11 @@ this in your configuration file:
|
||||
|
||||
$cfg['idf_mimetypes_db'] = '/home/mime.types';
|
||||
|
||||
## FreeBSD Installation
|
||||
|
||||
You need to install `/usr/ports/lang/php5-extensions` which contains
|
||||
the Standard PHP Library (SPL).
|
||||
|
||||
## Using a SMTP server with authentication
|
||||
|
||||
If your SMTP server requires authentication, for example,
|
||||
@@ -177,3 +183,33 @@ If your SMTP server requires authentication, for example,
|
||||
|
||||
Check with your provider to get the right settings.
|
||||
|
||||
## Git Daemon on Ubuntu Karmic
|
||||
|
||||
If you have problems getting it to run, you can follow this procedure
|
||||
proposed by Mathias in ticket 369.
|
||||
|
||||
1. Install git-daemon-run in addition to git-core
|
||||
2. Edit /etc/sv/git-daemon/run to look as follows:
|
||||
|
||||
#!/bin/sh
|
||||
exec 2>&1
|
||||
echo 'git-daemon starting.'
|
||||
exec chpst -ugit:git \
|
||||
/usr/lib/git-core/git-daemon \
|
||||
--reuseaddr \
|
||||
--syslog \
|
||||
--verbose \
|
||||
--base-path=/home/git/repositories \
|
||||
/home/git/repositories
|
||||
|
||||
3. Restart git-daemon-run
|
||||
|
||||
sv restart git-daemon
|
||||
|
||||
## If Subversion is not working
|
||||
|
||||
If you access a Subversion server with a self-signed certificate, you
|
||||
may have problems as your certificate is not trusted, check the
|
||||
[procedure provided here][svnfix] to solve the problem.
|
||||
|
||||
[svnfix]: http://projects.ceondo.com/p/indefero/issues/319/#ic1358
|
@@ -70,6 +70,13 @@ folder. Here is a configuration example:
|
||||
$cfg['idf_plugin_syncgit_path_gitserve'] = '/home/www/indefero/scripts/gitserve.py'; # yes .py
|
||||
$cfg['idf_plugin_syncgit_path_authorized_keys'] = '/home/git/.ssh/authorized_keys';
|
||||
$cfg['idf_plugin_syncgit_sync_file'] = '/tmp/SYNC-GIT';
|
||||
# Remove the git repositories which do not have a corresponding project
|
||||
# This is run at cron time
|
||||
$cfg['idf_plugin_syncgit_remove_orphans'] = false;
|
||||
# git account home dir
|
||||
$cfg['idf_plugin_syncgit_git_home_dir'] = '/home/git';
|
||||
# where are going to be the git repositories
|
||||
$cfg['idf_plugin_syncgit_base_repositories'] = '/home/git/repositories';
|
||||
|
||||
When someone will change his SSH key or add a new one, the
|
||||
`/tmp/SYNC-GIT` file will be created. The cron job
|
||||
|
@@ -67,6 +67,14 @@ You also need to provide the base definition of the hgrc file. For example:
|
||||
'extensions' => array(),
|
||||
);
|
||||
|
||||
If you are note using Apache but Nginx, you may need to create the
|
||||
passwords as plain text passwords (see ticket 391). You can configure
|
||||
the password storage with the format you want. The default is `sha`
|
||||
you can set it to `plain` for nginx.
|
||||
|
||||
$cfg['idf_plugin_syncmercurial_passwd_mode'] = 'sha';
|
||||
|
||||
See the [`FILE_PASSWD_*` constants](http://euk1.php.net/package/File_Passwd/docs/latest/File_Passwd/_File_Passwd-1.1.7---Passwd.php.html) for more choices.
|
||||
|
||||
## Cron configuration
|
||||
|
||||
@@ -76,3 +84,13 @@ Each time this file is modified, a temporary file is created.
|
||||
*/5 * * * * /bin/sh /home/indefero/src/scripts/SyncMercurial.sh
|
||||
|
||||
Edit this script and add correct values to `private_notify` and `reload_cmd`.
|
||||
|
||||
## Hook configuratin
|
||||
|
||||
To get notifications sent directly when pushing in your repositories,
|
||||
you need to add the following in your `.hgrc` file. The script will be
|
||||
called onec per push and will automatically send the notifications and
|
||||
sync the timeline.
|
||||
|
||||
[hooks]
|
||||
changegroup = /home/indefero/src/scripts/hgchangegroup.php
|
||||
|
@@ -66,6 +66,8 @@ need to put the following in your configuration file:
|
||||
$cfg['idf_plugin_syncsvn_authz_file'] = '/home/svn/dav_svn.authz';
|
||||
$cfg['idf_plugin_syncsvn_passwd_file'] = '/home/svn/dav_svn.passwd';
|
||||
$cfg['idf_plugin_syncsvn_svn_path'] = '/home/svn/repositories';
|
||||
// Delete the corresponding repository when deleting the project
|
||||
$cfg['idf_plugin_syncsvn_remove_orphans'] = false;
|
||||
|
||||
You can have more control over the permissions given to the owners,
|
||||
members, extra authorized users and anonymous users if you want with
|
||||
|
248
logo/indefero-logo5.svg
Normal file
248
logo/indefero-logo5.svg
Normal file
@@ -0,0 +1,248 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="2500.0901"
|
||||
height="1052.3622"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docname="indefero-logo5.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.0">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3535">
|
||||
<stop
|
||||
style="stop-color:#8ae234;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3537" />
|
||||
<stop
|
||||
style="stop-color:#8ae234;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3539" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3527">
|
||||
<stop
|
||||
style="stop-color:#9f5e21;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3529" />
|
||||
<stop
|
||||
style="stop-color:#9f5e21;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3531" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3309">
|
||||
<stop
|
||||
style="stop-color:#73d213;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3311" />
|
||||
<stop
|
||||
style="stop-color:#4e9a06;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3313" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3300">
|
||||
<stop
|
||||
style="stop-color:#a56223;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3302" />
|
||||
<stop
|
||||
style="stop-color:#492902;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3304" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3214">
|
||||
<stop
|
||||
style="stop-color:#c17d11;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3216" />
|
||||
<stop
|
||||
style="stop-color:#c17d11;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3218" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3200">
|
||||
<stop
|
||||
id="stop3204"
|
||||
offset="1"
|
||||
style="stop-color:#feaf36;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3178">
|
||||
<stop
|
||||
style="stop-color:#8f5902;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3180" />
|
||||
<stop
|
||||
style="stop-color:#8f5902;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3182" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective10" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3300"
|
||||
id="linearGradient3502"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="255.2104"
|
||||
y1="743.95398"
|
||||
x2="517.18134"
|
||||
y2="334.32626" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3309"
|
||||
id="linearGradient3505"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.90055,0,0,0.9256685,8.702072,50.919096)"
|
||||
x1="314.81146"
|
||||
y1="549.55981"
|
||||
x2="603.79364"
|
||||
y2="130.80347" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3527"
|
||||
id="linearGradient3533"
|
||||
x1="344.48004"
|
||||
y1="526.93384"
|
||||
x2="279.66428"
|
||||
y2="343.77176"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3535"
|
||||
id="linearGradient3541"
|
||||
x1="189.38306"
|
||||
y1="542.79291"
|
||||
x2="213.16689"
|
||||
y2="515.03833"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
gridtolerance="10000"
|
||||
guidetolerance="10"
|
||||
objecttolerance="10"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.26121807"
|
||||
inkscape:cx="54.404882"
|
||||
inkscape:cy="468.48648"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1279"
|
||||
inkscape:window-height="951"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="opacity:1;fill:#2e1c09;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect3479"
|
||||
width="2327.0989"
|
||||
height="738.08856"
|
||||
x="28.861307"
|
||||
y="47.247032"
|
||||
ry="0"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero.net/media/idfn/img/indefero-logo.png"
|
||||
inkscape:export-xdpi="10.974293"
|
||||
inkscape:export-ydpi="10.974293" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3505);fill-opacity:1;fill-rule:nonzero;stroke:#4e9a06;stroke-width:8.6737175;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 380.09452,80.164434 C 325.61878,80.164434 277.73831,109.63179 250.44346,154.01542 C 173.08362,161.38346 112.57489,224.77008 112.57489,301.77525 C 112.57489,328.86745 120.06848,354.27485 133.14683,376.14693 C 107.0966,405.29318 91.243109,443.82739 91.243109,486.07006 C 91.243109,576.90189 164.55915,650.60763 254.88993,650.60763 C 271.09473,650.60763 286.73713,648.22781 301.52154,643.80975 C 339.34139,666.58702 385.02955,679.88189 434.18381,679.88189 C 564.58392,679.88189 670.40931,586.17696 670.40933,470.70975 C 670.40933,424.81133 653.66603,382.36023 625.32555,347.85618 C 628.73221,333.4146 630.53185,318.20844 630.53185,302.49843 C 630.53185,212.12462 570.29216,138.17535 494.43623,133.1011 C 466.29611,100.61828 425.47491,80.164434 380.09452,80.164434 z"
|
||||
id="path2397"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero.net/media/idfn/img/indefero-logo.png"
|
||||
inkscape:export-xdpi="10.974293"
|
||||
inkscape:export-ydpi="10.974293" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3502);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.40000010000000019;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 480.78826,286.70465 C 471.74217,303.14801 466.59919,316.91871 462.21007,324.32034 C 458.4305,332.41806 437.64848,381.27668 422.04792,410.85567 C 411.43569,432.35724 400.69212,454.31445 384.28125,472.09375 C 378.04049,477.37818 367.78727,475.23418 363.26933,468.71428 C 353.17919,458.89555 343.45836,448.70244 333.24758,439.0075 C 317.77144,422.84753 305.56098,403.5827 297.62915,382.65768 C 289.88676,365.17614 282.06423,347.03016 268.29833,333.33399 C 266.87079,332.00892 257.87723,342.72971 251.17151,350.13535 C 257.91944,385.02379 261.45712,393.83832 272.16171,424.59112 C 277.97988,444.06591 287.52802,462.10601 295.01596,480.9416 C 301.95377,497.73482 307.73336,515.11749 310.44798,533.13227 C 316.97458,571.06863 313.78852,610.29702 303.54294,647.28446 C 295.53018,678.50408 283.87873,708.83248 268.40625,737.125 C 267.48586,741.82958 273.28765,745.0451 277.32903,743.60868 C 316.10441,740.6132 354.85515,736.72668 393.76368,736.01019 C 432.08809,735.62752 470.30781,739.07963 508.44819,742.41755 C 512.60098,742.7876 516.75356,743.16004 520.90625,743.53125 C 522.73666,738.32781 518.93119,733.37885 515.5,729.84375 C 505.37922,718.85052 495.85001,707.33025 486.04792,696.05659 C 472.12065,679.28224 459.49275,660.74518 453.48949,639.55179 C 445.74909,613.54378 446.01072,585.89039 449.3871,559.18722 C 454.13621,520.65521 457.70434,476.90793 468.12716,439.5747 C 475.03595,414.82825 499.26944,325.16045 505.28557,302.9463 C 506.6387,297.45482 507.70151,291.88947 508.4375,286.28125 C 508.3006,286.02979 501.31023,285.50092 480.78826,286.70465 z"
|
||||
id="rect2383"
|
||||
sodipodi:nodetypes="ccscscscccccccccccccccsccc"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero.net/media/idfn/img/indefero-logo.png"
|
||||
inkscape:export-xdpi="10.974293"
|
||||
inkscape:export-ydpi="10.974293" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3533);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.25000000000000000pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 261.61445,343.77177 C 258.29796,347.16111 256.78029,348.5143 253.80525,350.94005 C 257.34812,367.72635 271.24491,410.33512 274.92704,420.91638 C 283.98781,446.95407 298.27703,470.44926 305.96388,496.81755 C 312.6285,519.6793 316.95796,541.99153 318.18734,565.63445 C 319.43684,589.66412 317.35056,617.16231 311.24725,640.25675 C 304.22544,666.82669 289.67219,709.81256 278.71119,735.38821 C 291.85032,736.74081 303.9092,734.30172 317.58611,733.28738 C 330.8032,732.91089 346.51711,728.41602 360.28427,728.58961 C 361.70248,692.98386 362.28914,639.87401 361.91883,606.08799 C 361.53577,571.13943 356.10739,550.49134 343.0934,518.4162 C 332.76842,492.96857 313.62977,457.39972 298.73254,430.34797 C 283.83531,403.29622 270.0195,371.02282 261.61445,343.77177 z"
|
||||
id="path3450"
|
||||
sodipodi:nodetypes="ccsssscccsssc"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero.net/media/idfn/img/indefero-logo.png"
|
||||
inkscape:export-xdpi="10.974293"
|
||||
inkscape:export-ydpi="10.974293" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3541);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.25000000000000000pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 113.16529,429.39362 C 113.16529,429.39362 104.64326,454.1652 103.03794,468.69107 C 101.44344,483.11903 102.46825,506.23771 105.4804,520.43755 C 108.98801,536.97308 121.29761,558.93795 130.281,573.25668 C 138.61935,586.54728 158.09648,604.51753 171.10612,613.28778 C 185.25725,622.82754 205.57955,633.4095 222.19789,637.29436 C 239.00231,641.22271 255.43702,641.52676 272.63495,640.09436 C 278.21565,639.62955 302.26007,633.26385 302.26007,633.26385 L 308.87233,606.09973 L 113.16529,429.39362 z"
|
||||
id="path3461"
|
||||
sodipodi:nodetypes="cssssssccc"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero.net/media/idfn/img/indefero-logo.png"
|
||||
inkscape:export-xdpi="10.974293"
|
||||
inkscape:export-ydpi="10.974293" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:500px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr-tb;text-anchor:start;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:FromageCondOblique;-inkscape-font-specification:FromageCondOblique"
|
||||
x="739.95435"
|
||||
y="534.80164"
|
||||
id="text3481"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero.net/media/idfn/img/indefero-logo.png"
|
||||
inkscape:export-xdpi="10.974293"
|
||||
inkscape:export-ydpi="10.974293"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3483"
|
||||
x="739.95435"
|
||||
y="534.80164">indefero</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:150px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:FromageCondOblique;-inkscape-font-specification:FromageCondOblique"
|
||||
x="744.05432"
|
||||
y="711.55402"
|
||||
id="text3485"
|
||||
sodipodi:linespacing="125%"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero.net/media/idfn/img/indefero-logo.png"
|
||||
inkscape:export-xdpi="10.974293"
|
||||
inkscape:export-ydpi="10.974293"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3487"
|
||||
x="744.05432"
|
||||
y="711.55402"
|
||||
style="letter-spacing:5.01085806">Better code management</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
24
scripts/git-post-update
Executable file
24
scripts/git-post-update
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This hook does only one thing:
|
||||
#
|
||||
# 1. It calls the gitpostupdate.php script with the current $GIT_DIR
|
||||
# as argument. The gitpostupdate.php script will then trigger
|
||||
# the 'gitpostupdate.php::run' event with the $GIT_DIR as argument
|
||||
# together with merged $_ENV and $_SERVER array.
|
||||
#
|
||||
# This hook is normally installed automatically at the creation of your
|
||||
# repository if you have everything configured correctly. If you want
|
||||
# to enable it later, you need to symlink it as "post-update" in your
|
||||
# $GIT_DIR/hooks folder.
|
||||
#
|
||||
# www$ chmod +x /home/www/indefero/scripts/git-post-update
|
||||
# git$ cd /home/git/repositories/project.git/hooks
|
||||
# git$ ln -s /home/www/indefero/scripts/git-post-update post-update
|
||||
#
|
||||
|
||||
SCRIPTDIR=$(dirname $(readlink -f $0))
|
||||
FULL_GIT_DIR=$(readlink -f $GIT_DIR)
|
||||
PHP_POST_UPDATE=$SCRIPTDIR/gitpostupdate.php
|
||||
|
||||
echo php $PHP_POST_UPDATE $FULL_GIT_DIR | at now > /dev/null 2>&1
|
@@ -22,18 +22,12 @@
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* This script is used to control the access to the git repositories
|
||||
* using a restricted shell access.
|
||||
* This script is used to sync the SSH keys, mark the repositories for
|
||||
* export and prune the deleted repositories.
|
||||
*
|
||||
* The only argument must be the login of the user.
|
||||
*/
|
||||
// Set the include path to have Pluf and IDF in it.
|
||||
$indefero_path = dirname(__FILE__).'/../src';
|
||||
//$pluf_path = '/path/to/pluf/src';
|
||||
set_include_path(get_include_path()
|
||||
.PATH_SEPARATOR.$indefero_path
|
||||
// .PATH_SEPARATOR.$pluf_path
|
||||
);
|
||||
|
||||
require dirname(__FILE__).'/../src/IDF/conf/path.php';
|
||||
require 'Pluf.php';
|
||||
Pluf::start(dirname(__FILE__).'/../src/IDF/conf/idf.php');
|
||||
Pluf_Dispatcher::loadControllers(Pluf::f('idf_views'));
|
||||
|
58
scripts/gitpostupdate.php
Normal file
58
scripts/gitpostupdate.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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-2010 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 ***** */
|
||||
|
||||
/**
|
||||
* This script will send the notifications after a push in your
|
||||
* repository.
|
||||
*/
|
||||
|
||||
require dirname(__FILE__).'/../src/IDF/conf/path.php';
|
||||
require 'Pluf.php';
|
||||
Pluf::start(dirname(__FILE__).'/../src/IDF/conf/idf.php');
|
||||
Pluf_Dispatcher::loadControllers(Pluf::f('idf_views'));
|
||||
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* gitpostupdate.php::run
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* gitpostupdate.php
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform a set of tasks on a
|
||||
* post update of a git repository.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('git_dir' => '/path/to/git/repository.git',
|
||||
* 'env' => array_merge($_ENV, $_SERVER));
|
||||
*
|
||||
*/
|
||||
$params = array('git_dir' => $argv[1],
|
||||
'env' => array_merge($_ENV, $_SERVER));
|
||||
Pluf_Signal::send('gitpostupdate.php::run', 'gitpostupdate.php', $params);
|
||||
|
||||
|
@@ -27,13 +27,8 @@
|
||||
*
|
||||
* The only argument must be the login of the user.
|
||||
*/
|
||||
// Set the include path to have Pluf and IDF in it.
|
||||
$indefero_path = dirname(__FILE__).'/../src';
|
||||
//$pluf_path = '/path/to/pluf/src';
|
||||
set_include_path(get_include_path()
|
||||
.PATH_SEPARATOR.$indefero_path
|
||||
// .PATH_SEPARATOR.$pluf_path
|
||||
);
|
||||
|
||||
require dirname(__FILE__).'/../src/IDF/conf/path.php';
|
||||
require 'Pluf.php';
|
||||
Pluf::start(dirname(__FILE__).'/../src/IDF/conf/idf.php');
|
||||
Pluf_Dispatcher::loadControllers(Pluf::f('idf_views'));
|
||||
|
61
scripts/hgchangegroup.php
Executable file
61
scripts/hgchangegroup.php
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env php
|
||||
<?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-2010 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 ***** */
|
||||
|
||||
/**
|
||||
* This script will send the notifications after a push in your
|
||||
* repository.
|
||||
*/
|
||||
|
||||
require dirname(__FILE__).'/../src/IDF/conf/path.php';
|
||||
require 'Pluf.php';
|
||||
Pluf::start(dirname(__FILE__).'/../src/IDF/conf/idf.php');
|
||||
Pluf_Dispatcher::loadControllers(Pluf::f('idf_views'));
|
||||
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* hgchangegroup.php::run
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* hgchangegroup.php
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform a set of tasks on a
|
||||
* group change hook of a Mercurial repository. The rel_dir is a
|
||||
* relative path to the root of your hg repositories but starting with
|
||||
* a slash.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('rel_dir' => '/relative/path/to/hg/repository',
|
||||
* 'env' => array_merge($_ENV, $_SERVER));
|
||||
*
|
||||
*/
|
||||
$params = array('rel_dir' => $_ENV['PATH_INFO'],
|
||||
'env' => array_merge($_ENV, $_SERVER));
|
||||
Pluf_Signal::send('hgchangegroup.php::run', 'hgchangegroup.php', $params);
|
||||
|
||||
|
24
scripts/svn-post-commit
Executable file
24
scripts/svn-post-commit
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This hook does only one thing:
|
||||
#
|
||||
# 1. It calls the svnpostcommit.php script with the current repository
|
||||
# and revision as argument. The svnpostcommit.php script will then
|
||||
# trigger the 'svnpostcommit.php::run' event with the repository path
|
||||
# and revision as arguments together with merged $_ENV and $_SERVER
|
||||
# array.
|
||||
#
|
||||
# This hook is normally installed automatically at the creation of your
|
||||
# repository if you have everything configured correctly. If you want
|
||||
# to enable it later, you need to symlink it as "post-commit" in your
|
||||
# $REPOSITORY/hooks folder.
|
||||
#
|
||||
# www$ chmod +x /home/www/indefero/scripts/svn-post-commit
|
||||
# www$ cd /home/svn/repositories/project/hooks
|
||||
# www$ ln -s /home/www/indefero/scripts/svn-post-commit post-commit
|
||||
#
|
||||
|
||||
SCRIPTDIR=$(dirname $(readlink -f $0))
|
||||
PHP_POST_COMMIT=$SCRIPTDIR/svnpostcommit.php
|
||||
|
||||
echo php $PHP_POST_COMMIT "$1" "$2" | at now > /dev/null 2>&1
|
61
scripts/svnpostcommit.php
Normal file
61
scripts/svnpostcommit.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?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-2010 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 ***** */
|
||||
|
||||
/**
|
||||
* This script will send the notifications after a push in your
|
||||
* repository.
|
||||
*/
|
||||
|
||||
require dirname(__FILE__).'/../src/IDF/conf/path.php';
|
||||
require 'Pluf.php';
|
||||
Pluf::start(dirname(__FILE__).'/../src/IDF/conf/idf.php');
|
||||
Pluf_Dispatcher::loadControllers(Pluf::f('idf_views'));
|
||||
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* svnpostcommit.php::run
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* svnpostcommit.php
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform a set of tasks on a
|
||||
* post commit of a subversion repository.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('repo_dir' => '/path/to/subversion/repository',
|
||||
* 'revision' => 1234,
|
||||
* 'env' => array_merge($_ENV, $_SERVER));
|
||||
*
|
||||
*/
|
||||
$params = array('repo_dir' => $argv[1],
|
||||
'revision' => $argv[2],
|
||||
'env' => array_merge($_ENV, $_SERVER));
|
||||
Pluf_Signal::send('svnpostcommit.php::run', 'svnpostcommit.php', $params);
|
||||
|
||||
|
||||
|
@@ -13,7 +13,7 @@
|
||||
# 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.
|
||||
n# 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
|
||||
@@ -144,38 +144,58 @@ class IDF_Commit extends Pluf_Model
|
||||
if ($r->count() > 0) {
|
||||
return $r[0];
|
||||
}
|
||||
if (!isset($change->full_message)) {
|
||||
$change->full_message = '';
|
||||
}
|
||||
$scm = IDF_Scm::get($project);
|
||||
$commit = new IDF_Commit();
|
||||
$commit->project = $project;
|
||||
$commit->scm_id = $change->commit;
|
||||
$commit->summary = $change->title;
|
||||
$commit->fullmessage = $change->full_message;
|
||||
$commit->summary = self::toUTF8($change->title);
|
||||
$commit->fullmessage = self::toUTF8($change->full_message);
|
||||
$commit->author = $scm->findAuthor($change->author);
|
||||
$commit->origauthor = $change->author;
|
||||
$commit->creation_dtime = $change->date;
|
||||
$commit->create();
|
||||
// We notify the creation of the commit
|
||||
if ('' != $project->getConf()->getVal('source_notification_email', '')) {
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'c' => $commit,
|
||||
'project' => $project,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/source/commit-created-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'),
|
||||
$project->getConf()->getVal('source_notification_email'),
|
||||
sprintf(__('New Commit %s - %s (%s)'),
|
||||
$commit->scm_id, $commit->summary, $project->shortname));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
}
|
||||
|
||||
$commit->notify($project->getConf());
|
||||
return $commit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert encoding to UTF8.
|
||||
*
|
||||
* If an array is given, the encoding is detected only on the
|
||||
* first value and then used to convert all the strings.
|
||||
*
|
||||
* @param mixed String or array of string to be converted
|
||||
* @param bool Returns the encoding together with the converted text (false)
|
||||
* @return mixed String or array of string or array of res + encoding
|
||||
*/
|
||||
public static function toUTF8($text, $get_encoding=False)
|
||||
{
|
||||
$enc = 'ASCII, UTF-8, ISO-8859-1, JIS, EUC-JP, SJIS';
|
||||
$ref = $text;
|
||||
if (is_array($text)) {
|
||||
$ref = $text[0];
|
||||
}
|
||||
if (Pluf_Text_UTF8::check($ref)) {
|
||||
return (!$get_encoding) ? $text : array($text, 'UTF-8');
|
||||
}
|
||||
$encoding = mb_detect_encoding($ref, $enc, true);
|
||||
if ($encoding == false) {
|
||||
$encoding = Pluf_Text_UTF8::detect_cyr_charset($ref);
|
||||
}
|
||||
if (is_array($text)) {
|
||||
foreach ($text as $t) {
|
||||
$res[] = mb_convert_encoding($t, 'UTF-8', $encoding);
|
||||
}
|
||||
return (!$get_encoding) ? $res : array($res, $encoding);
|
||||
} else {
|
||||
$res = mb_convert_encoding($text, 'UTF-8', $encoding);
|
||||
return (!$get_encoding) ? $res : array($res, $encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timeline fragment for the commit.
|
||||
*
|
||||
@@ -202,7 +222,7 @@ class IDF_Commit extends Pluf_Model
|
||||
</tr>
|
||||
<tr class="extra">
|
||||
<td colspan="2">
|
||||
<div class="helptext right">'.__('Commit').' <a href="'.$url.'" class="mono">'.$this->scm_id.'</a>, '.__('by').' '.$user.'</div></td></tr>';
|
||||
<div class="helptext right">'.sprintf(__('Commit %s, by %s'), '<a href="'.$url.'" class="mono">'.$this->scm_id.'</a>', $user).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
|
||||
@@ -218,23 +238,55 @@ class IDF_Commit extends Pluf_Model
|
||||
.Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit',
|
||||
array($request->project->shortname,
|
||||
$this->scm_id));
|
||||
$tag = new IDF_Template_IssueComment();
|
||||
$summary = '<content type="xhtml">'."\n"
|
||||
.'<div xmlns="http://www.w3.org/1999/xhtml">'
|
||||
.$tag->start($this->summary, $request, false, false, false);
|
||||
if ($this->fullmessage) {
|
||||
$summary .= '<br /><br />'
|
||||
.$tag->start($this->fullmessage, $request, false, false, false);
|
||||
}
|
||||
$date = Pluf_Date::gmDateToGmString($this->creation_dtime);
|
||||
$summary .= '</div></content>';
|
||||
$out = '<entry>
|
||||
<title>'.Pluf_esc($request->project->name).': '.__('Commit').' '.$this->scm_id.'</title>
|
||||
<link href="'.$url.'"/>
|
||||
<id>'.$url.'</id>
|
||||
<updated>'.$date.'</updated>'.$summary.'
|
||||
</entry>
|
||||
';
|
||||
return $out;
|
||||
$author = ($this->get_author()) ?
|
||||
$this->get_author() : $this->origauthor;
|
||||
$cproject = $this->get_project();
|
||||
$context = new Pluf_Template_Context_Request(
|
||||
$request,
|
||||
array(
|
||||
'c' => $this,
|
||||
'cproject' => $cproject,
|
||||
'url' => $url,
|
||||
'date' => $date,
|
||||
'author' => $author,
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/source/feedfragment.xml');
|
||||
return $tmpl->render($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification of change of the object.
|
||||
*
|
||||
* @param IDF_Conf Current configuration
|
||||
* @param bool Creation (true)
|
||||
*/
|
||||
public function notify($conf, $create=true)
|
||||
{
|
||||
if ('' == $conf->getVal('source_notification_email', '')) {
|
||||
return;
|
||||
}
|
||||
$current_locale = Pluf_Translation::getLocale();
|
||||
$langs = Pluf::f('languages', array('en'));
|
||||
Pluf_Translation::loadSetLocale($langs[0]);
|
||||
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'c' => $this,
|
||||
'project' => $this->get_project(),
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/source/commit-created-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'),
|
||||
$conf->getVal('source_notification_email'),
|
||||
sprintf(__('New Commit %s - %s (%s)'),
|
||||
$this->scm_id, $this->summary,
|
||||
$this->get_project()->shortname));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
Pluf_Translation::loadSetLocale($current_locale);
|
||||
}
|
||||
}
|
||||
|
@@ -187,10 +187,10 @@ class IDF_Diff
|
||||
*/
|
||||
public static function getChunk($line)
|
||||
{
|
||||
$elts = split(' ', $line);
|
||||
$elts = explode(' ', $line);
|
||||
$res = array();
|
||||
for ($i=1;$i<3;$i++) {
|
||||
$res[] = split(',', trim(substr($elts[$i], 1)));
|
||||
$res[] = explode(',', trim(substr($elts[$i], 1)));
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
@@ -133,6 +133,16 @@ class IDF_Form_Admin_ProjectCreate extends Pluf_Form
|
||||
'IDF_Form_Admin_ProjectCreate', $params);
|
||||
}
|
||||
|
||||
public function clean_owners()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['owners']);
|
||||
}
|
||||
|
||||
public function clean_members()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['members']);
|
||||
}
|
||||
|
||||
public function clean_svn_remote_url()
|
||||
{
|
||||
$this->cleaned_data['svn_remote_url'] = (!empty($this->cleaned_data['svn_remote_url'])) ? $this->cleaned_data['svn_remote_url'] : '';
|
||||
@@ -148,7 +158,7 @@ class IDF_Form_Admin_ProjectCreate extends Pluf_Form
|
||||
|
||||
public function clean_shortname()
|
||||
{
|
||||
$shortname = $this->cleaned_data['shortname'];
|
||||
$shortname = mb_strtolower($this->cleaned_data['shortname']);
|
||||
if (preg_match('/[^\-A-Za-z0-9]/', $shortname)) {
|
||||
throw new Pluf_Form_Invalid(__('This shortname contains illegal characters, please use only letters, digits and dash (-).'));
|
||||
}
|
||||
@@ -208,7 +218,7 @@ class IDF_Form_Admin_ProjectCreate extends Pluf_Form
|
||||
$project->name = $this->cleaned_data['name'];
|
||||
$project->shortname = $this->cleaned_data['shortname'];
|
||||
$project->private = $this->cleaned_data['private_project'];
|
||||
$project->description = __('Click on the Administer tab to set the description of your project.');
|
||||
$project->description = __('Click on the Project Management tab to set the description of your project.');
|
||||
$project->create();
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($project);
|
||||
|
@@ -61,6 +61,16 @@ class IDF_Form_Admin_ProjectUpdate extends Pluf_Form
|
||||
));
|
||||
}
|
||||
|
||||
public function clean_owners()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['owners']);
|
||||
}
|
||||
|
||||
public function clean_members()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['members']);
|
||||
}
|
||||
|
||||
public function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
|
214
src/IDF/Form/Admin/UserCreate.php
Normal file
214
src/IDF/Form/Admin/UserCreate.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Allow an admin to create a user.
|
||||
*/
|
||||
class IDF_Form_Admin_UserCreate extends Pluf_Form
|
||||
{
|
||||
public $request = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->request = $extra['request'];
|
||||
$this->fields['first_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('First name'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['last_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Last name'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['login'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Login'),
|
||||
'max_length' => 15,
|
||||
'min_length' => 3,
|
||||
'initial' => '',
|
||||
'help_text' => __('The login must be between 3 and 15 characters long and contains only letters and digits.'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 15,
|
||||
'size' => 10,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['email'] = new Pluf_Form_Field_Email(
|
||||
array('required' => true,
|
||||
'label' => __('Email'),
|
||||
'initial' => '',
|
||||
'help_text' => __('Double check the email address as the password is directly sent to the user.'),
|
||||
));
|
||||
|
||||
$this->fields['language'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Language'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_SelectInput',
|
||||
'widget_attrs' => array(
|
||||
'choices' =>
|
||||
Pluf_L10n::getInstalledLanguages()
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['ssh_key'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Add a public SSH key'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('rows' => 3,
|
||||
'cols' => 40),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'help_text' => __('Be careful to provide the public key and not the private key!')
|
||||
));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
$password = Pluf_Utils::getPassword();
|
||||
$user = new Pluf_User();
|
||||
$user->setFromFormData($this->cleaned_data);
|
||||
$user->active = true;
|
||||
$user->staff = false;
|
||||
$user->administrator = false;
|
||||
$user->setPassword($password);
|
||||
$user->create();
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* Pluf_User::passwordUpdated
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_Admin_UserCreate
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal is sent when a user is created
|
||||
* by the staff.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('user' => $user)
|
||||
*
|
||||
*/
|
||||
$params = array('user' => $user);
|
||||
Pluf_Signal::send('Pluf_User::passwordUpdated',
|
||||
'IDF_Form_Admin_UserCreate', $params);
|
||||
// Create the ssh key as needed
|
||||
if ('' !== $this->cleaned_data['ssh_key']) {
|
||||
$key = new IDF_Key();
|
||||
$key->user = $user;
|
||||
$key->content = $this->cleaned_data['ssh_key'];
|
||||
$key->create();
|
||||
}
|
||||
// Send an email to the user with the password
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::login', array(), array(), false);
|
||||
$context = new Pluf_Template_Context(
|
||||
array('password' => Pluf_Template::markSafe($password),
|
||||
'user' => $user,
|
||||
'url' => Pluf_Template::markSafe($url),
|
||||
'admin' => $this->request->user,
|
||||
));
|
||||
$tmpl = new Pluf_Template('idf/gadmin/users/createuser-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $user->email,
|
||||
__('Your details to access your forge.'));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
return $user;
|
||||
}
|
||||
|
||||
function clean_ssh_key()
|
||||
{
|
||||
return IDF_Form_UserAccount::checkSshKey($this->cleaned_data['ssh_key']);
|
||||
}
|
||||
|
||||
function clean_last_name()
|
||||
{
|
||||
$last_name = trim($this->cleaned_data['last_name']);
|
||||
if ($last_name == mb_strtoupper($last_name)) {
|
||||
return mb_convert_case(mb_strtolower($last_name),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
return $last_name;
|
||||
}
|
||||
|
||||
function clean_first_name()
|
||||
{
|
||||
$first_name = trim($this->cleaned_data['first_name']);
|
||||
if ($first_name == mb_strtoupper($first_name)) {
|
||||
return mb_convert_case(mb_strtolower($first_name),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
return $first_name;
|
||||
}
|
||||
|
||||
function clean_email()
|
||||
{
|
||||
$this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email']));
|
||||
$guser = new Pluf_User();
|
||||
$sql = new Pluf_SQL('email=%s', array($this->cleaned_data['email']));
|
||||
if ($guser->getCount(array('filter' => $sql->gen())) > 0) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used.'), $this->cleaned_data['email']));
|
||||
}
|
||||
return $this->cleaned_data['email'];
|
||||
}
|
||||
|
||||
public function clean_login()
|
||||
{
|
||||
$this->cleaned_data['login'] = mb_strtolower(trim($this->cleaned_data['login']));
|
||||
if (preg_match('/[^a-z0-9]/', $this->cleaned_data['login'])) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The login "%s" can only contain letters and digits.'), $this->cleaned_data['login']));
|
||||
}
|
||||
$guser = new Pluf_User();
|
||||
$sql = new Pluf_SQL('login=%s', $this->cleaned_data['login']);
|
||||
if ($guser->getCount(array('filter' => $sql->gen())) > 0) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The login "%s" is already used, please find another one.'), $this->cleaned_data['login']));
|
||||
}
|
||||
return $this->cleaned_data['login'];
|
||||
}
|
||||
}
|
@@ -179,9 +179,12 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
|
||||
function clean_first_name()
|
||||
{
|
||||
$first_name = trim($this->cleaned_data['first_name']);
|
||||
if ($first_name == '---') {
|
||||
throw new Pluf_Form_Invalid(__('--- is not a valid first name.'));
|
||||
}
|
||||
if ($first_name == mb_strtoupper($first_name)) {
|
||||
return mb_convert_case(mb_strtolower($first_name),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
$first_name = mb_convert_case(mb_strtolower($first_name),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
return $first_name;
|
||||
}
|
||||
|
@@ -141,7 +141,7 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_issue_one_max', IDF_Form_IssueTrackingConf::init_one_max)) as $class) {
|
||||
foreach (explode(',', $conf->getVal('labels_issue_one_max', IDF_Form_IssueTrackingConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
|
@@ -67,6 +67,45 @@ class IDF_Form_MembersConf extends Pluf_Form
|
||||
$this->project->membershipsUpdated();
|
||||
}
|
||||
|
||||
public function clean_owners()
|
||||
{
|
||||
return self::checkBadLogins($this->cleaned_data['owners']);
|
||||
}
|
||||
|
||||
public function clean_members()
|
||||
{
|
||||
return self::checkBadLogins($this->cleaned_data['members']);
|
||||
}
|
||||
|
||||
/**
|
||||
* From the input, find the bad logins.
|
||||
*
|
||||
* @throws Pluf_Form_Invalid exception when bad logins are found
|
||||
* @param string Comma, new line delimited list of logins
|
||||
* @return string Comma, new line delimited list of logins
|
||||
*/
|
||||
public static function checkBadLogins($logins)
|
||||
{
|
||||
$bad = array();
|
||||
foreach (preg_split("/\015\012|\015|\012|\,/", $logins, -1, PREG_SPLIT_NO_EMPTY) as $login) {
|
||||
$sql = new Pluf_SQL('login=%s', array(trim($login)));
|
||||
try {
|
||||
$user = Pluf::factory('Pluf_User')->getOne(array('filter'=>$sql->gen()));
|
||||
if (null == $user) {
|
||||
$bad[] = $login;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$bad[] = $login;
|
||||
}
|
||||
}
|
||||
$n = count($bad);
|
||||
if ($n) {
|
||||
$badlogins = Pluf_esc(implode(', ', $bad));
|
||||
throw new Pluf_Form_Invalid(sprintf(_n('The following login is invalid: %s.', 'The following login are invalids: %s.', $n), $badlogins));
|
||||
}
|
||||
return $logins;
|
||||
}
|
||||
|
||||
/**
|
||||
* The update of the memberships is done in different places. This
|
||||
* avoids duplicating code.
|
||||
|
@@ -48,6 +48,21 @@ class IDF_Form_Password extends Pluf_Form
|
||||
if ($users->count() == 0) {
|
||||
throw new Pluf_Form_Invalid(__('Sorry, we cannot find a user with this email address or login. Feel free to try again.'));
|
||||
}
|
||||
$ok = false;
|
||||
foreach ($users as $user) {
|
||||
if ($user->active) {
|
||||
$ok = true;
|
||||
continue;
|
||||
}
|
||||
if (!$user->active and $user->first_name == '---') {
|
||||
$ok = true;
|
||||
continue;
|
||||
}
|
||||
$ok = false; // This ensures an all or nothing ok.
|
||||
}
|
||||
if (!$ok) {
|
||||
throw new Pluf_Form_Invalid(__('Sorry, we cannot find a user with this email address or login. Feel free to try again.'));
|
||||
}
|
||||
return $account;
|
||||
}
|
||||
|
||||
@@ -64,23 +79,34 @@ class IDF_Form_Password extends Pluf_Form
|
||||
$sql = new Pluf_SQL('email=%s OR login=%s',
|
||||
array($account, $account));
|
||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||
|
||||
$return_url = '';
|
||||
foreach ($users as $user) {
|
||||
$tmpl = new Pluf_Template('idf/user/passrecovery-email.txt');
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
$code = trim($cr->encrypt($user->email.':'.$user->id.':'.time()),
|
||||
'~');
|
||||
$code = substr(md5(Pluf::f('secret_key').$code), 0, 2).$code;
|
||||
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecovery', array($code), array(), false);
|
||||
$urlic = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryInputCode', array(), array(), false);
|
||||
$context = new Pluf_Template_Context(array('url' => Pluf_Template::markSafe($url),
|
||||
'urlik' => Pluf_Template::markSafe($urlic),
|
||||
'user' => Pluf_Template::markSafe($user),
|
||||
'key' => Pluf_Template::markSafe($code)));
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $user->email,
|
||||
__('Password Recovery - InDefero'));
|
||||
$email->setReturnPath(Pluf::f('bounce_email', Pluf::f('from_email')));
|
||||
$email->addTextMessage($tmpl->render($context));
|
||||
$email->sendMail();
|
||||
if ($user->active) {
|
||||
$return_url = Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryInputCode');
|
||||
$tmpl = new Pluf_Template('idf/user/passrecovery-email.txt');
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
$code = trim($cr->encrypt($user->email.':'.$user->id.':'.time()),
|
||||
'~');
|
||||
$code = substr(md5(Pluf::f('secret_key').$code), 0, 2).$code;
|
||||
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecovery', array($code), array(), false);
|
||||
$urlic = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryInputCode', array(), array(), false);
|
||||
$context = new Pluf_Template_Context(
|
||||
array('url' => Pluf_Template::markSafe($url),
|
||||
'urlik' => Pluf_Template::markSafe($urlic),
|
||||
'user' => Pluf_Template::markSafe($user),
|
||||
'key' => Pluf_Template::markSafe($code)));
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $user->email,
|
||||
__('Password Recovery - InDefero'));
|
||||
$email->setReturnPath(Pluf::f('bounce_email', Pluf::f('from_email')));
|
||||
$email->addTextMessage($tmpl->render($context));
|
||||
$email->sendMail();
|
||||
}
|
||||
if (!$user->active and $user->first_name == '---') {
|
||||
$return_url = Pluf_HTTP_URL_urlForView('IDF_Views::registerInputKey');
|
||||
IDF_Form_Register::sendVerificationEmail($user);
|
||||
}
|
||||
}
|
||||
return $return_url;
|
||||
}
|
||||
}
|
||||
|
@@ -95,6 +95,10 @@ class IDF_Form_PasswordInputKey extends Pluf_Form
|
||||
return false;
|
||||
}
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
return split(':', $cr->decrypt($encrypted), 3);
|
||||
$f = explode(':', $cr->decrypt($encrypted), 3);
|
||||
if (count($f) != 3) {
|
||||
return false;
|
||||
}
|
||||
return $f;
|
||||
}
|
||||
}
|
||||
|
@@ -73,6 +73,9 @@ class IDF_Form_PasswordReset extends Pluf_Form
|
||||
if ($this->cleaned_data['password'] != $this->cleaned_data['password2']) {
|
||||
throw new Pluf_Form_Invalid(__('The two passwords must be the same.'));
|
||||
}
|
||||
if (!$this->user->active) {
|
||||
throw new Pluf_Form_Invalid(__('This account is not active. Please contact the forge administrator to activate it.'));
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
|
@@ -124,8 +124,14 @@ class IDF_Form_Register extends Pluf_Form
|
||||
$user->language = $this->request->language_code;
|
||||
$user->active = false;
|
||||
$user->create();
|
||||
$from_email = Pluf::f('from_email');
|
||||
self::sendVerificationEmail($user);
|
||||
return $user;
|
||||
}
|
||||
|
||||
public static function sendVerificationEmail($user)
|
||||
{
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
$from_email = Pluf::f('from_email');
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
$encrypted = trim($cr->encrypt($user->email.':'.$user->id), '~');
|
||||
$key = substr(md5(Pluf::f('secret_key').$encrypted), 0, 2).$encrypted;
|
||||
@@ -144,6 +150,5 @@ class IDF_Form_Register extends Pluf_Form
|
||||
__('Confirm the creation of your account.'));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
@@ -91,6 +91,6 @@ class IDF_Form_RegisterInputKey extends Pluf_Form
|
||||
return false;
|
||||
}
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
return split(':', $cr->decrypt($encrypted), 2);
|
||||
return explode(':', $cr->decrypt($encrypted), 2);
|
||||
}
|
||||
}
|
||||
|
@@ -1,203 +0,0 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* Create a new documentation page.
|
||||
*
|
||||
* This create a new page and the corresponding revision.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiCreate extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $show_full = false;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$initial = __('# Introduction
|
||||
|
||||
Add your content here.
|
||||
|
||||
|
||||
# Details
|
||||
|
||||
Add your content here. Format your content with:
|
||||
|
||||
* Text in **bold** or *italic*.
|
||||
* Headings, paragraphs, and lists.
|
||||
* Links to other [[WikiPage]].
|
||||
');
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
}
|
||||
$this->fields['title'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Page title'),
|
||||
'initial' => __('PageName'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
'help_text' => __('The page name must contains only letters, digits and the dash (-) character.'),
|
||||
));
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'help_text' => __('This one line description is displayed in the list of pages.'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Content'),
|
||||
'initial' => $initial,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 26,
|
||||
),
|
||||
));
|
||||
|
||||
if ($this->show_full) {
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function clean_title()
|
||||
{
|
||||
$title = $this->cleaned_data['title'];
|
||||
if (preg_match('/[^a-zA-Z0-9\-]/', $title)) {
|
||||
throw new Pluf_Form_Invalid(__('The title contains invalid characters.'));
|
||||
}
|
||||
$sql = new Pluf_SQL('project=%s AND title=%s',
|
||||
array($this->project->id, $title));
|
||||
$pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() > 0) {
|
||||
throw new Pluf_Form_Invalid(__('A page with this title already exists.'));
|
||||
}
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if (!$this->show_full) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than label from the %s class to a page.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// Add a tag for each label
|
||||
$tags = array();
|
||||
if ($this->show_full) {
|
||||
for ($i=1;$i<4;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tags[] = IDF_Tag::add($name, $this->project, $class);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create the page
|
||||
$page = new IDF_WikiPage();
|
||||
$page->project = $this->project;
|
||||
$page->submitter = $this->user;
|
||||
$page->summary = trim($this->cleaned_data['summary']);
|
||||
$page->title = trim($this->cleaned_data['title']);
|
||||
$page->create();
|
||||
foreach ($tags as $tag) {
|
||||
$page->setAssoc($tag);
|
||||
}
|
||||
// add the first revision
|
||||
$rev = new IDF_WikiRevision();
|
||||
$rev->wikipage = $page;
|
||||
$rev->content = $this->cleaned_data['content'];
|
||||
$rev->submitter = $this->user;
|
||||
$rev->summary = __('Initial page creation');
|
||||
$rev->create();
|
||||
return $page;
|
||||
}
|
||||
}
|
@@ -204,26 +204,7 @@ class IDF_Form_ReviewCreate extends Pluf_Form
|
||||
$patch->commit = self::findCommit($this->cleaned_data['commit']);
|
||||
$patch->patch = $this->cleaned_data['patch'];
|
||||
$patch->create();
|
||||
// Send create notification
|
||||
if ('' != $this->project->getConf()->getVal('review_notification_email', '')) {
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'review' => $review,
|
||||
'patch' => $patch,
|
||||
'comments' => array(),
|
||||
'project' => $this->project,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/review/review-created-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'),
|
||||
$this->project->getConf()->getVal('review_notification_email'),
|
||||
sprintf(__('New Code Review %s - %s (%s)'),
|
||||
$review->id, $review->summary, $this->project->shortname));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
}
|
||||
$patch->notify($this->project->getConf());
|
||||
return $review;
|
||||
}
|
||||
|
||||
|
@@ -30,12 +30,15 @@ class IDF_Form_ReviewFileComment extends Pluf_Form
|
||||
public $files = null;
|
||||
public $patch = null;
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->files = $extra['files'];
|
||||
$this->patch = $extra['patch'];
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
|
||||
foreach ($this->files as $filename => $def) {
|
||||
$this->fields[md5($filename)] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
@@ -48,6 +51,41 @@ class IDF_Form_ReviewFileComment extends Pluf_Form
|
||||
),
|
||||
));
|
||||
}
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('General comment'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 9,
|
||||
),
|
||||
));
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
}
|
||||
if ($this->show_full) {
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Summary'),
|
||||
'initial' => $this->patch->get_review()->summary,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['status'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Status'),
|
||||
'initial' => $this->patch->get_review()->get_status()->name,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 20,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +102,16 @@ class IDF_Form_ReviewFileComment extends Pluf_Form
|
||||
throw new Pluf_Form_Invalid(__('You need to provide comments on at least one file.'));
|
||||
}
|
||||
|
||||
function clean_content()
|
||||
{
|
||||
$content = trim($this->cleaned_data['content']);
|
||||
if (!$this->show_full and strlen($content) == 0) {
|
||||
throw new Pluf_Form_Invalid(__('You need to provide your general comment about the proposal.'));
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
@@ -76,19 +124,40 @@ class IDF_Form_ReviewFileComment extends Pluf_Form
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// create a base comment
|
||||
$bc = new IDF_Review_Comment();
|
||||
$bc->patch = $this->patch;
|
||||
$bc->submitter = $this->user;
|
||||
$bc->content = $this->cleaned_data['content'];
|
||||
$review = $this->patch->get_review();
|
||||
if ($this->show_full) {
|
||||
// Compare between the old and the new data
|
||||
// Status, summary
|
||||
$changes = array();
|
||||
$status = IDF_Tag::add(trim($this->cleaned_data['status']), $this->project, 'Status');
|
||||
if ($status->id != $this->patch->get_review()->status) {
|
||||
$changes['st'] = $status->name;
|
||||
}
|
||||
if (trim($this->patch->get_review()->summary) != trim($this->cleaned_data['summary'])) {
|
||||
$changes['su'] = trim($this->cleaned_data['summary']);
|
||||
}
|
||||
// Update the review
|
||||
$review->summary = trim($this->cleaned_data['summary']);
|
||||
$review->status = $status;
|
||||
$bc->changes = $changes;
|
||||
}
|
||||
$bc->create();
|
||||
foreach ($this->files as $filename => $def) {
|
||||
if (!empty($this->cleaned_data[md5($filename)])) {
|
||||
// Add a comment.
|
||||
$c = new IDF_Review_FileComment();
|
||||
$c->patch = $this->patch;
|
||||
$c->comment = $bc;
|
||||
$c->cfile = $filename;
|
||||
$c->submitter = $this->user;
|
||||
$c->content = $this->cleaned_data[md5($filename)];
|
||||
$c->create();
|
||||
}
|
||||
}
|
||||
$this->patch->get_review()->update(); // reindex and put up in
|
||||
// the list.
|
||||
return $this->patch;
|
||||
$review->update(); // reindex and put up in the list.
|
||||
return $bc;
|
||||
}
|
||||
}
|
||||
|
@@ -86,6 +86,11 @@ class IDF_Form_TabsConf extends Pluf_Form
|
||||
));
|
||||
}
|
||||
|
||||
public function clean_authorized_users()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['authorized_users']);
|
||||
}
|
||||
|
||||
public function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
|
@@ -46,6 +46,16 @@ class IDF_Form_UpdateUpload extends Pluf_Form
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['changelog'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Description'),
|
||||
'initial' => $this->upload->changelog,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 13,
|
||||
),
|
||||
));
|
||||
$tags = $this->upload->get_tags_list();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$initial = '';
|
||||
@@ -76,7 +86,7 @@ class IDF_Form_UpdateUpload extends Pluf_Form
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
|
||||
foreach (explode(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
@@ -132,6 +142,7 @@ class IDF_Form_UpdateUpload extends Pluf_Form
|
||||
}
|
||||
// Create the upload
|
||||
$this->upload->summary = trim($this->cleaned_data['summary']);
|
||||
$this->upload->changelog = trim($this->cleaned_data['changelog']);
|
||||
$this->upload->modif_dtime = gmdate('Y-m-d H:i:s');
|
||||
$this->upload->update();
|
||||
$this->upload->batchAssoc('IDF_Tag', $tags);
|
||||
|
@@ -44,6 +44,16 @@ class IDF_Form_Upload extends Pluf_Form
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['changelog'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Description'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 13,
|
||||
),
|
||||
));
|
||||
$this->fields['file'] = new Pluf_Form_Field_File(
|
||||
array('required' => true,
|
||||
'label' => __('File'),
|
||||
@@ -71,7 +81,8 @@ class IDF_Form_Upload extends Pluf_Form
|
||||
{
|
||||
$extra = strtolower(implode('|', explode(' ', Pluf::f('idf_extra_upload_ext'))));
|
||||
if (strlen($extra)) $extra .= '|';
|
||||
if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|wmv|zip)$/i', $this->cleaned_data['file'])) {
|
||||
if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $this->cleaned_data['file'])) {
|
||||
@unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']);
|
||||
throw new Pluf_Form_Invalid(__('For security reason, you cannot upload a file with this extension.'));
|
||||
}
|
||||
return $this->cleaned_data['file'];
|
||||
@@ -85,7 +96,7 @@ class IDF_Form_Upload extends Pluf_Form
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
|
||||
foreach (explode(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
@@ -155,6 +166,7 @@ class IDF_Form_Upload extends Pluf_Form
|
||||
$upload->project = $this->project;
|
||||
$upload->submitter = $this->user;
|
||||
$upload->summary = trim($this->cleaned_data['summary']);
|
||||
$upload->changelog = trim($this->cleaned_data['changelog']);
|
||||
$upload->file = $this->cleaned_data['file'];
|
||||
$upload->filesize = filesize(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']);
|
||||
$upload->downloads = 0;
|
||||
@@ -163,21 +175,7 @@ class IDF_Form_Upload extends Pluf_Form
|
||||
$upload->setAssoc($tag);
|
||||
}
|
||||
// Send the notification
|
||||
if ('' != $this->project->getConf()->getVal('downloads_notification_email', '')) {
|
||||
$context = new Pluf_Template_Context(
|
||||
array('file' => $upload,
|
||||
'urlfile' => $upload->getAbsoluteUrl($this->project),
|
||||
'project' => $this->project,
|
||||
'tags' => $upload->get_tags_list(),
|
||||
));
|
||||
$tmpl = new Pluf_Template('idf/downloads/download-created-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $this->project->getConf()->getVal('downloads_notification_email'),
|
||||
sprintf(__('New download - %s (%s)'),
|
||||
$upload->summary, $this->project->shortname));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
}
|
||||
$upload->notify($this->project->getConf());
|
||||
return $upload;
|
||||
}
|
||||
}
|
||||
|
@@ -94,7 +94,7 @@ class IDF_Form_UserAccount extends Pluf_Form
|
||||
|
||||
$this->fields['ssh_key'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Your public SSH key'),
|
||||
'label' => __('Add a public SSH key'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('rows' => 3,
|
||||
'cols' => 40),
|
||||
@@ -105,7 +105,6 @@ class IDF_Form_UserAccount extends Pluf_Form
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
@@ -151,22 +150,17 @@ class IDF_Form_UserAccount extends Pluf_Form
|
||||
$this->user->setMessage(sprintf(__('A validation email has been sent to "%s" to validate the email address change.'), Pluf_esc($new_email)));
|
||||
}
|
||||
$this->user->setFromFormData($this->cleaned_data);
|
||||
// Get keys
|
||||
$keys = $this->user->get_idf_key_list();
|
||||
if ($keys->count() > 0) {
|
||||
$key = $keys[0];
|
||||
} else {
|
||||
// Add key as needed.
|
||||
if ('' !== $this->cleaned_data['ssh_key']) {
|
||||
$key = new IDF_Key();
|
||||
$key->user = $this->user;
|
||||
}
|
||||
$key->content = $this->cleaned_data['ssh_key'];
|
||||
if ($commit) {
|
||||
$this->user->update();
|
||||
if ($key->id != '') {
|
||||
$key->update();
|
||||
} else {
|
||||
$key->content = $this->cleaned_data['ssh_key'];
|
||||
if ($commit) {
|
||||
$key->create();
|
||||
}
|
||||
}
|
||||
if ($commit) {
|
||||
$this->user->update();
|
||||
if ($update_pass) {
|
||||
/**
|
||||
* [signal]
|
||||
@@ -195,6 +189,57 @@ class IDF_Form_UserAccount extends Pluf_Form
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check an ssh key.
|
||||
*
|
||||
* It will throw a Pluf_Form_Invalid exception if it cannot
|
||||
* validate the key.
|
||||
*
|
||||
* @param $key string The key
|
||||
* @param $user int The user id of the user of the key (0)
|
||||
* @return string The clean key
|
||||
*/
|
||||
public static function checkSshKey($key, $user=0)
|
||||
{
|
||||
$key = trim($key);
|
||||
if (strlen($key) == 0) {
|
||||
return '';
|
||||
}
|
||||
$key = str_replace(array("\n", "\r"), '', $key);
|
||||
if (!preg_match('#^ssh\-[a-z]{3}\s(\S+)\s\S+$#', $key, $matches)) {
|
||||
throw new Pluf_Form_Invalid(__('The format of the key is not valid. It must start with ssh-dss or ssh-rsa, a long string on a single line and at the end a comment.'));
|
||||
}
|
||||
if (Pluf::f('idf_strong_key_check', false)) {
|
||||
$tmpfile = Pluf::f('tmp_folder', '/tmp').'/'.$user.'-key';
|
||||
file_put_contents($tmpfile, $key, LOCK_EX);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').
|
||||
'ssh-keygen -l -f '.escapeshellarg($tmpfile).' > /dev/null 2>&1';
|
||||
exec($cmd, $out, $return);
|
||||
unlink($tmpfile);
|
||||
if ($return != 0) {
|
||||
throw new Pluf_Form_Invalid(__('Please check the key as it does not appears to be a valid key.'));
|
||||
}
|
||||
}
|
||||
// If $user, then check if not the same key stored
|
||||
if ($user) {
|
||||
$ruser = Pluf::factory('Pluf_User', $user);
|
||||
if ($ruser->id > 0) {
|
||||
$sql = new Pluf_SQL('content=%s', array($key));
|
||||
$keys = Pluf::factory('IDF_Key')->getList(array('filter' => $sql->gen()));
|
||||
if (count($keys) > 0) {
|
||||
throw new Pluf_Form_Invalid(__('You already have uploaded this SSH key.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
|
||||
function clean_ssh_key()
|
||||
{
|
||||
return self::checkSshKey($this->cleaned_data['ssh_key'],
|
||||
$this->user->id);
|
||||
}
|
||||
|
||||
function clean_last_name()
|
||||
{
|
||||
$last_name = trim($this->cleaned_data['last_name']);
|
||||
|
@@ -63,7 +63,7 @@ class IDF_Form_UserChangeEmail extends Pluf_Form
|
||||
throw new Pluf_Form_Invalid(__('The validation key is not valid. Please copy/paste it from your confirmation email.'));
|
||||
}
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
return split(':', $cr->decrypt($encrypted), 3);
|
||||
return explode(':', $cr->decrypt($encrypted), 3);
|
||||
|
||||
}
|
||||
|
||||
|
@@ -127,7 +127,7 @@ Add your content here. Format your content with:
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) {
|
||||
foreach (explode(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
@@ -199,25 +199,7 @@ Add your content here. Format your content with:
|
||||
$rev->submitter = $this->user;
|
||||
$rev->summary = __('Initial page creation');
|
||||
$rev->create();
|
||||
// send the notification
|
||||
if ('' != $this->project->getConf()->getVal('wiki_notification_email', '')) {
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'page' => $page,
|
||||
'rev' => $rev,
|
||||
'project' => $this->project,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/wiki/wiki-created-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'),
|
||||
$this->project->getConf()->getVal('wiki_notification_email'),
|
||||
sprintf(__('New Documentation Page %s - %s (%s)'),
|
||||
$page->title, $page->summary, $this->project->shortname));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
}
|
||||
$rev->notify($this->project->getConf());
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
|
64
src/IDF/Form/WikiDelete.php
Normal file
64
src/IDF/Form/WikiDelete.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* Delete a documentation page.
|
||||
*
|
||||
* This is a hard delete of the page and the revisions.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiDelete extends Pluf_Form
|
||||
{
|
||||
protected $page = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->page = $extra['page'];
|
||||
$this->fields['confirm'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => true,
|
||||
'label' => __('Yes, I understand that the page and all its revisions will be deleted.'),
|
||||
'initial' => '',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the confirmation.
|
||||
*/
|
||||
public function clean_confirm()
|
||||
{
|
||||
if (!$this->cleaned_data['confirm']) {
|
||||
throw new Pluf_Form_Invalid(__('You need to confirm the deletion.'));
|
||||
}
|
||||
return $this->cleaned_data['confirm'];
|
||||
}
|
||||
|
||||
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
$this->page->delete();
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -138,7 +138,7 @@ class IDF_Form_WikiUpdate extends Pluf_Form
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) {
|
||||
foreach (explode(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
@@ -236,25 +236,7 @@ class IDF_Form_WikiUpdate extends Pluf_Form
|
||||
$rev->summary = $this->cleaned_data['comment'];
|
||||
$rev->changes = $changes;
|
||||
$rev->create();
|
||||
// send the notification
|
||||
if ('' != $this->project->getConf()->getVal('wiki_notification_email', '')) {
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'page' => $this->page,
|
||||
'rev' => $rev,
|
||||
'project' => $this->project,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/wiki/wiki-updated-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'),
|
||||
$this->project->getConf()->getVal('wiki_notification_email'),
|
||||
sprintf(__('Documentation Page Changed %s - %s (%s)'),
|
||||
$this->page->title, $this->page->summary, $this->project->shortname));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
}
|
||||
$rev->notify($this->project->getConf(), false);
|
||||
return $this->page;
|
||||
}
|
||||
}
|
||||
|
@@ -193,38 +193,134 @@ class IDF_Issue extends Pluf_Model
|
||||
$ic = (in_array($this->status, $request->project->getTagIdsByStatus('closed'))) ? 'issue-c' : 'issue-o';
|
||||
$out .= sprintf(__('<a href="%1$s" class="%2$s" title="View issue">Issue %3$d</a>, %4$s'), $url, $ic, $this->id, Pluf_esc($this->summary)).'</td>';
|
||||
$out .= "\n".'<tr class="extra"><td colspan="2">
|
||||
<div class="helptext right">'.sprintf(__('Creation of <a href="%s" class="%s">issue %d</a>'), $url, $ic, $this->id).', '.__('by').' '.$user.'</div></td></tr>';
|
||||
<div class="helptext right">'.sprintf(__('Creation of <a href="%s" class="%s">issue %d</a>, by %s'), $url, $ic, $this->id, $user).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
|
||||
public function feedFragment($request)
|
||||
{
|
||||
$base = '<entry>
|
||||
<title>%%title%%</title>
|
||||
<link href="%%url%%"/>
|
||||
<id>%%url%%</id>
|
||||
<updated>%%date%%</updated>
|
||||
<content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
|
||||
<pre>%%content%%</pre>
|
||||
</div></content>
|
||||
</entry>';
|
||||
$url = Pluf::f('url_base')
|
||||
.Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||
array($request->project->shortname,
|
||||
$this->id));
|
||||
$title = sprintf(__('%s: Issue %d created - %s'),
|
||||
Pluf_esc($request->project->name),
|
||||
$this->id, Pluf_esc($this->summary));
|
||||
// Get the first comment of this issue.
|
||||
$request->project->name,
|
||||
$this->id, $this->summary);
|
||||
$cts = $this->get_comments_list(array('order' => 'id ASC',
|
||||
'nb' => 1));
|
||||
$tag = new IDF_Template_IssueComment();
|
||||
$content = $tag->start($cts[0]->content, $request, false);
|
||||
$date = Pluf_Date::gmDateToGmString($this->creation_dtime);
|
||||
return Pluf_Translation::sprintf($base,
|
||||
array('url' => $url,
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'date' => $date));
|
||||
$context = new Pluf_Template_Context_Request(
|
||||
$request,
|
||||
array('url' => $url,
|
||||
'author' => $this->get_submitter(),
|
||||
'title' => $title,
|
||||
'c' => $cts[0],
|
||||
'issue' => $this,
|
||||
'date' => $date)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/issues/feedfragment.xml');
|
||||
return $tmpl->render($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification of change of the object.
|
||||
*
|
||||
* For the moment, only email, but one can add webhooks later.
|
||||
*
|
||||
* Usage:
|
||||
* <pre>
|
||||
* $this->notify($conf); // Notify the creation
|
||||
* $this->notify($conf, false); // Notify the update of the object
|
||||
* </pre>
|
||||
*
|
||||
* @param IDF_Conf Current configuration
|
||||
* @param bool Creation (true)
|
||||
*/
|
||||
public function notify($conf, $create=true)
|
||||
{
|
||||
$prj = $this->get_project();
|
||||
$to_email = array();
|
||||
if ('' != $conf->getVal('issues_notification_email', '')) {
|
||||
$langs = Pluf::f('languages', array('en'));
|
||||
$to_email[] = array($conf->getVal('issues_notification_email'),
|
||||
$langs[0]);
|
||||
}
|
||||
$current_locale = Pluf_Translation::getLocale();
|
||||
$id = '<'.md5($this->id.md5(Pluf::f('secret_key'))).'@'.Pluf::f('mail_host', 'localhost').'>';
|
||||
if ($create) {
|
||||
if (null != $this->get_owner() and $this->owner != $this->submitter) {
|
||||
$email_lang = array($this->get_owner()->email,
|
||||
$this->get_owner()->language);
|
||||
if (!in_array($email_lang, $to_email)) {
|
||||
$to_email[] = $email_lang;
|
||||
}
|
||||
}
|
||||
$comments = $this->get_comments_list(array('order' => 'id ASC'));
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'issue' => $this,
|
||||
'comment' => $comments[0],
|
||||
'project' => $prj,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
foreach ($to_email as $email_lang) {
|
||||
Pluf_Translation::loadSetLocale($email_lang[1]);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $email_lang[0],
|
||||
sprintf(__('Issue %s - %s (%s)'),
|
||||
$this->id, $this->summary, $prj->shortname));
|
||||
$tmpl = new Pluf_Template('idf/issues/issue-created-email.txt');
|
||||
$email->addTextMessage($tmpl->render($context));
|
||||
$email->addHeaders(array('Message-ID'=>$id));
|
||||
$email->sendMail();
|
||||
}
|
||||
} else {
|
||||
$comments = $this->get_comments_list(array('order' => 'id DESC'));
|
||||
$email_sender = '';
|
||||
if (isset($comments[0])) {
|
||||
$email_sender = $comments[0]->get_submitter()->email;
|
||||
}
|
||||
foreach ($this->get_interested_list() as $interested) {
|
||||
$email_lang = array($interested->email,
|
||||
$interested->language);
|
||||
if (!in_array($email_lang, $to_email)) {
|
||||
$to_email[] = $email_lang;
|
||||
}
|
||||
}
|
||||
$email_lang = array($this->get_submitter()->email,
|
||||
$this->get_submitter()->language);
|
||||
if (!in_array($email_lang, $to_email)) {
|
||||
$to_email[] = $email_lang;
|
||||
}
|
||||
if (null != $this->get_owner()) {
|
||||
$email_lang = array($this->get_owner()->email,
|
||||
$this->get_owner()->language);
|
||||
if (!in_array($email_lang, $to_email)) {
|
||||
$to_email[] = $email_lang;
|
||||
}
|
||||
}
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'issue' => $this,
|
||||
'comments' => $comments,
|
||||
'project' => $prj,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
));
|
||||
foreach ($to_email as $email_lang) {
|
||||
if ($email_lang[0] == $email_sender) {
|
||||
continue; // Do not notify the one having created
|
||||
// the comment
|
||||
}
|
||||
Pluf_Translation::loadSetLocale($email_lang[1]);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $email_lang[0],
|
||||
sprintf(__('Updated Issue %s - %s (%s)'),
|
||||
$this->id, $this->summary, $prj->shortname));
|
||||
$tmpl = new Pluf_Template('idf/issues/issue-updated-email.txt');
|
||||
$email->addTextMessage($tmpl->render($context));
|
||||
$email->addHeaders(array('References'=>$id));
|
||||
$email->sendMail();
|
||||
}
|
||||
}
|
||||
Pluf_Translation::loadSetLocale($current_locale);
|
||||
}
|
||||
}
|
@@ -167,66 +167,33 @@ class IDF_IssueComment extends Pluf_Model
|
||||
$out .= '</div>';
|
||||
}
|
||||
$out .= '</td></tr>';
|
||||
|
||||
|
||||
$out .= "\n".'<tr class="extra"><td colspan="2">
|
||||
<div class="helptext right">'.sprintf(__('Comment on <a href="%s" class="%s">issue %d</a>'), $url, $ic, $issue->id).', '.__('by').' '.$user.'</div></td></tr>';
|
||||
|
||||
<div class="helptext right">'.sprintf(__('Comment on <a href="%s" class="%s">issue %d</a>, by %s'), $url, $ic, $issue->id, $user).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
|
||||
public function feedFragment($request)
|
||||
{
|
||||
$base = '<entry>
|
||||
<title>%%title%%</title>
|
||||
<link href="%%url%%"/>
|
||||
<id>%%url%%</id>
|
||||
<updated>%%date%%</updated>
|
||||
<content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
|
||||
%%content%%
|
||||
</div></content>
|
||||
</entry>';
|
||||
$issue = $this->get_issue();
|
||||
$url = Pluf::f('url_base')
|
||||
.Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||
array($request->project->shortname,
|
||||
$issue->id));
|
||||
$url .= '#ic'.$this->id;
|
||||
$title = sprintf(__('%s: Comment on issue %d - %s'),
|
||||
Pluf_esc($request->project->name),
|
||||
$issue->id, Pluf_esc($issue->summary));
|
||||
$submitter = $this->get_submitter();
|
||||
$tag = new IDF_Template_IssueComment();
|
||||
$content = '<p><pre>'.$tag->start($this->content, $request, false).'</pre></p>';
|
||||
if ($this->changedIssue()) {
|
||||
$content .= '<p>';
|
||||
foreach ($this->changes as $w => $v) {
|
||||
$content .= '<strong>';
|
||||
switch ($w) {
|
||||
case 'su':
|
||||
$content .= __('Summary:'); break;
|
||||
case 'st':
|
||||
$content .= __('Status:'); break;
|
||||
case 'ow':
|
||||
$content .= __('Owner:'); break;
|
||||
case 'lb':
|
||||
$content .= __('Labels:'); break;
|
||||
}
|
||||
$content .= '</strong> ';
|
||||
if ($w == 'lb') {
|
||||
$content .= Pluf_esc(implode(', ', $v));
|
||||
} else {
|
||||
$content .= Pluf_esc($v);
|
||||
}
|
||||
$content .= ' ';
|
||||
}
|
||||
$content .= '</p>';
|
||||
}
|
||||
$url .= '#ic'.$this->id;
|
||||
$date = Pluf_Date::gmDateToGmString($this->creation_dtime);
|
||||
return Pluf_Translation::sprintf($base,
|
||||
array('url' => $url,
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'date' => $date));
|
||||
$context = new Pluf_Template_Context_Request(
|
||||
$request,
|
||||
array('url' => $url,
|
||||
'author' => $issue->get_submitter(),
|
||||
'title' => $title,
|
||||
'c' => $this,
|
||||
'issue' => $issue,
|
||||
'date' => $date)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/issues/feedfragment.xml');
|
||||
return $tmpl->render($context);
|
||||
}
|
||||
}
|
||||
|
@@ -70,6 +70,11 @@ class IDF_Key extends Pluf_Model
|
||||
);
|
||||
}
|
||||
|
||||
function showCompact()
|
||||
{
|
||||
return Pluf_Template::markSafe(Pluf_esc(substr($this->content, 0, 25)).' [...] '.Pluf_esc(substr($this->content, -55)));
|
||||
}
|
||||
|
||||
function postSave($create=false)
|
||||
{
|
||||
/**
|
||||
@@ -97,4 +102,30 @@ class IDF_Key extends Pluf_Model
|
||||
'IDF_Key', $params);
|
||||
}
|
||||
|
||||
function preDelete()
|
||||
{
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Key::preDelete
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Key
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform special
|
||||
* operations before a key is deleted.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('key' => $key)
|
||||
*
|
||||
*/
|
||||
$params = array('key' => $this);
|
||||
Pluf_Signal::send('IDF_Key::preDelete',
|
||||
'IDF_Key', $params);
|
||||
}
|
||||
|
||||
}
|
||||
|
55
src/IDF/Migrations/12DownloadDesc.php
Normal file
55
src/IDF/Migrations/12DownloadDesc.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* Add the private column for the project.
|
||||
*/
|
||||
|
||||
function IDF_Migrations_12DownloadDesc_up($params=null)
|
||||
{
|
||||
$table = Pluf::factory('IDF_Upload')->getSqlTable();
|
||||
$sql = array();
|
||||
$sql['PostgreSQL'] = 'ALTER TABLE '.$table.' ADD COLUMN "changelog" TEXT DEFAULT \'\'';
|
||||
$sql['MySQL'] = 'ALTER TABLE '.$table.' ADD COLUMN `changelog` LONGTEXT DEFAULT \'\'';
|
||||
$db = Pluf::db();
|
||||
$engine = Pluf::f('db_engine');
|
||||
if (!isset($sql[$engine])) {
|
||||
throw new Exception('SQLite complex migration not supported.');
|
||||
}
|
||||
$db->execute($sql[$engine]);
|
||||
}
|
||||
|
||||
function IDF_Migrations_12DownloadDesc_down($params=null)
|
||||
{
|
||||
$table = Pluf::factory('IDF_Upload')->getSqlTable();
|
||||
$sql = array();
|
||||
$sql['PostgreSQL'] = 'ALTER TABLE '.$table.' DROP COLUMN "changelog"';
|
||||
$sql['MySQL'] = 'ALTER TABLE '.$table.' DROP COLUMN `changelog`';
|
||||
$db = Pluf::db();
|
||||
$engine = Pluf::f('db_engine');
|
||||
if (!isset($sql[$engine])) {
|
||||
throw new Exception('SQLite complex migration not supported.');
|
||||
}
|
||||
$db->execute($sql[$engine]);
|
||||
|
||||
}
|
60
src/IDF/Migrations/13NewReview.php
Normal file
60
src/IDF/Migrations/13NewReview.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* Remove the old review and add the new one.
|
||||
*
|
||||
* This is a destructive operation.
|
||||
*/
|
||||
|
||||
function IDF_Migrations_13NewReview_up($params=null)
|
||||
{
|
||||
$extra = (Pluf::f('db_engine') == 'PostgreSQL') ? ' CASCADE' : '';
|
||||
$pfx = Pluf::f('db_table_prefix');
|
||||
$tables = array('idf_review_filecomments',
|
||||
'idf_review_patches',
|
||||
'idf_review_pluf_user_assoc',
|
||||
'idf_review_idf_tag_assoc',
|
||||
'idf_reviews');
|
||||
$db = Pluf::db();
|
||||
foreach ($tables as $table) {
|
||||
$db->execute('DROP TABLE IF EXISTS '.$pfx.$table.$extra);
|
||||
}
|
||||
$models = array(
|
||||
'IDF_Review',
|
||||
'IDF_Review_Patch',
|
||||
'IDF_Review_Comment',
|
||||
'IDF_Review_FileComment',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
foreach ($models as $model) {
|
||||
$schema->model = new $model();
|
||||
$schema->createTables();
|
||||
}
|
||||
}
|
||||
|
||||
function IDF_Migrations_13NewReview_down($params=null)
|
||||
{
|
||||
// We do nothing as we cannot go back to the old reviews
|
||||
}
|
109
src/IDF/Migrations/Backup.php
Normal file
109
src/IDF/Migrations/Backup.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* Backup of InDefero.
|
||||
*
|
||||
* !! You need also to backup Pluf if you want the full backup. !!
|
||||
*
|
||||
* @param string Path to the folder where to store the backup
|
||||
* @param string Name of the backup (null)
|
||||
* @return int The backup was correctly written
|
||||
*/
|
||||
function IDF_Migrations_Backup_run($folder, $name=null)
|
||||
{
|
||||
$models = array(
|
||||
'IDF_Project',
|
||||
'IDF_Tag',
|
||||
'IDF_Issue',
|
||||
'IDF_IssueComment',
|
||||
'IDF_Conf',
|
||||
'IDF_Upload',
|
||||
'IDF_Search_Occ',
|
||||
'IDF_IssueFile',
|
||||
'IDF_Commit',
|
||||
'IDF_Timeline',
|
||||
'IDF_WikiPage',
|
||||
'IDF_WikiRevision',
|
||||
'IDF_Review',
|
||||
'IDF_Review_Patch',
|
||||
'IDF_Review_Comment',
|
||||
'IDF_Review_FileComment',
|
||||
'IDF_Key',
|
||||
'IDF_Scm_Cache_Git',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
// Now, for each table, we dump the content in json, this is a
|
||||
// memory intensive operation
|
||||
$to_json = array();
|
||||
foreach ($models as $model) {
|
||||
$to_json[$model] = Pluf_Test_Fixture::dump($model, false);
|
||||
}
|
||||
if (null == $name) {
|
||||
$name = date('Y-m-d');
|
||||
}
|
||||
return file_put_contents(sprintf('%s/%s-IDF.json', $folder, $name),
|
||||
json_encode($to_json), LOCK_EX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore IDF from a backup.
|
||||
*
|
||||
* @param string Path to the backup folder
|
||||
* @param string Backup name
|
||||
* @return bool Success
|
||||
*/
|
||||
function IDF_Migrations_Backup_restore($folder, $name)
|
||||
{
|
||||
$models = array(
|
||||
'IDF_Project',
|
||||
'IDF_Tag',
|
||||
'IDF_Issue',
|
||||
'IDF_IssueComment',
|
||||
'IDF_Conf',
|
||||
'IDF_Upload',
|
||||
'IDF_Search_Occ',
|
||||
'IDF_IssueFile',
|
||||
'IDF_Commit',
|
||||
'IDF_Timeline',
|
||||
'IDF_WikiPage',
|
||||
'IDF_WikiRevision',
|
||||
'IDF_Review',
|
||||
'IDF_Review_Patch',
|
||||
'IDF_Review_Comment',
|
||||
'IDF_Review_FileComment',
|
||||
'IDF_Key',
|
||||
'IDF_Scm_Cache_Git',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
foreach ($models as $model) {
|
||||
$schema->model = new $model();
|
||||
$schema->createTables();
|
||||
}
|
||||
$full_data = json_decode(file_get_contents(sprintf('%s/%s-IDF.json', $folder, $name)), true);
|
||||
foreach ($full_data as $model => $data) {
|
||||
Pluf_Test_Fixture::load($data, false);
|
||||
}
|
||||
return true;
|
||||
}
|
@@ -44,8 +44,10 @@ function IDF_Migrations_Install_setup($params=null)
|
||||
'IDF_WikiRevision',
|
||||
'IDF_Review',
|
||||
'IDF_Review_Patch',
|
||||
'IDF_Review_Comment',
|
||||
'IDF_Review_FileComment',
|
||||
'IDF_Key',
|
||||
'IDF_Scm_Cache_Git',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
@@ -83,8 +85,10 @@ function IDF_Migrations_Install_teardown($params=null)
|
||||
$perm = Pluf_Permission::getFromString('IDF.project-authorized-user');
|
||||
if ($perm) $perm->delete();
|
||||
$models = array(
|
||||
'IDF_Scm_Cache_Git',
|
||||
'IDF_Key',
|
||||
'IDF_Review_FileComment',
|
||||
'IDF_Review_Comment',
|
||||
'IDF_Review_Patch',
|
||||
'IDF_Review',
|
||||
'IDF_WikiRevision',
|
||||
|
@@ -44,9 +44,38 @@ class IDF_Plugin_SyncGit
|
||||
{
|
||||
// First check for the single mandatory config variable.
|
||||
if (!Pluf::f('idf_plugin_syncgit_sync_file', false)) {
|
||||
Pluf_Log::debug('IDF_Plugin_SyncGit plugin not configured.');
|
||||
return;
|
||||
}
|
||||
@touch(Pluf::f('idf_plugin_syncgit_sync_file'));
|
||||
@chmod(Pluf::f('idf_plugin_syncgit_sync_file'), 0666);
|
||||
if ($signal != 'gitpostupdate.php::run') {
|
||||
Pluf_Log::event('IDF_Plugin_SyncGit', 'create',
|
||||
Pluf::f('idf_plugin_syncgit_sync_file'));
|
||||
@touch(Pluf::f('idf_plugin_syncgit_sync_file'));
|
||||
@chmod(Pluf::f('idf_plugin_syncgit_sync_file'), 0777);
|
||||
} else {
|
||||
self::postUpdate($signal, $params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point for the post-update signal.
|
||||
*
|
||||
* It tries to find the name of the project, when found it runs an
|
||||
* update of the timeline.
|
||||
*/
|
||||
static public function postUpdate($signal, &$params)
|
||||
{
|
||||
// Chop the ".git" and get what is left
|
||||
$pname = basename($params['git_dir'], '.git');
|
||||
try {
|
||||
$project = IDF_Project::getOr404($pname);
|
||||
} catch (Pluf_HTTP_Error404 $e) {
|
||||
Pluf_Log::event(array('IDF_Plugin_SyncGit::postUpdate', 'Project not found.', array($pname, $params)));
|
||||
return false; // Project not found
|
||||
}
|
||||
// Now we have the project and can update the timeline
|
||||
Pluf_Log::debug(array('IDF_Plugin_SyncGit::postUpdate', 'Project found', $pname, $project->id));
|
||||
IDF_Scm::syncTimeline($project, true);
|
||||
Pluf_Log::event(array('IDF_Plugin_SyncGit::postUpdate', 'sync', array($pname, $project->id)));
|
||||
}
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ class IDF_Plugin_SyncGit_Cron
|
||||
$cmd = Pluf::f('idf_plugin_syncgit_path_gitserve', '/dev/null');
|
||||
$authorized_keys = Pluf::f('idf_plugin_syncgit_path_authorized_keys', false);
|
||||
if (false == $authorized_keys) {
|
||||
throw new Pluf_Exception_SettingError('Setting git_path_authorized_keys not set.');
|
||||
throw new Pluf_Exception_SettingError('Setting idf_plugin_syncgit_path_authorized_keys not set.');
|
||||
}
|
||||
if (!is_writable($authorized_keys)) {
|
||||
throw new Exception('Cannot create file: '.$authorized_keys);
|
||||
@@ -69,6 +69,44 @@ class IDF_Plugin_SyncGit_Cron
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove orphan repositories.
|
||||
*/
|
||||
public static function removeOrphanRepositories()
|
||||
{
|
||||
$path = Pluf::f('idf_plugin_syncgit_base_repositories', '/home/git/repositories');
|
||||
if (!is_dir($path) || is_link($path)) {
|
||||
throw new Pluf_Exception_SettingError(sprintf(
|
||||
'Directory %s does not exist! Setting "idf_plugin_syncgit_base_repositories not set.',
|
||||
$path));
|
||||
}
|
||||
if (!is_writable($path)) {
|
||||
throw new Exception(sprintf('Repository %s is not writable.', $path));
|
||||
}
|
||||
$projects = array();
|
||||
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
|
||||
$projects[] = $project->shortname;
|
||||
}
|
||||
unset($project);
|
||||
$it = new DirectoryIterator($path);
|
||||
$orphans = array();
|
||||
while ($it->valid()) {
|
||||
if (!$it->isDot() && $it->isDir() && !in_array(basename($it->getFileName(), '.git'), $projects)) {
|
||||
$orphans[] = $it->getPathName();
|
||||
}
|
||||
$it->next();
|
||||
}
|
||||
if (count($orphans)) {
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').'rm -rf '.implode(' ', $orphans);
|
||||
exec($cmd);
|
||||
while (list(, $project) = each($orphans)) {
|
||||
if (is_dir($project)) {
|
||||
throw new Exception(sprintf('Cannot remove %s directory.', $project));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a sync is needed.
|
||||
*
|
||||
@@ -79,6 +117,9 @@ class IDF_Plugin_SyncGit_Cron
|
||||
@unlink(Pluf::f('idf_plugin_syncgit_sync_file'));
|
||||
self::sync();
|
||||
self::markExport();
|
||||
if (Pluf::f('idf_plugin_syncgit_remove_orphans', false)) {
|
||||
self::removeOrphanRepositories();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -91,11 +91,14 @@ class IDF_Plugin_SyncGit_Serve
|
||||
// the repository on the fly
|
||||
$p = explode(DIRECTORY_SEPARATOR, $fullpath);
|
||||
$mpath = implode(DIRECTORY_SEPARATOR, array_slice($p, 0, -1));
|
||||
mkdir($mpath, 0750, true);
|
||||
if (!file_exists($mpath)) {
|
||||
mkdir($mpath, 0750, true);
|
||||
}
|
||||
$this->initRepository($fullpath);
|
||||
$this->setGitExport($relpath, $fullpath);
|
||||
}
|
||||
$new_cmd = sprintf("%s '%s'", $verb, $fullpath);
|
||||
Pluf_Log::info(array('IDF_Plugin_Git_Serve::serve', $username, $cmd, $new_cmd));
|
||||
return $new_cmd;
|
||||
}
|
||||
|
||||
@@ -159,7 +162,7 @@ class IDF_Plugin_SyncGit_Serve
|
||||
$request->user = $user;
|
||||
$request->conf = $conf;
|
||||
$request->project = $project;
|
||||
if (true === IDF_Precondition::accessTabGeneric($request, 'source_access_rights')) {
|
||||
if (true === IDF_Precondition::accessSource($request)) {
|
||||
if ($mode == 'readonly') {
|
||||
return array(Pluf::f('idf_plugin_syncgit_base_repositories', '/home/git/repositories'),
|
||||
$project->shortname);
|
||||
@@ -190,13 +193,39 @@ class IDF_Plugin_SyncGit_Serve
|
||||
*/
|
||||
public function initRepository($fullpath)
|
||||
{
|
||||
mkdir($fullpath, 0750, true);
|
||||
if (!file_exists($fullpath)) {
|
||||
mkdir($fullpath, 0750, true);
|
||||
}
|
||||
exec(sprintf(Pluf::f('idf_exec_cmd_prefix', '').
|
||||
Pluf::f('git_path', 'git').' --git-dir=%s init', escapeshellarg($fullpath)),
|
||||
$out, $res);
|
||||
if ($res != 0) {
|
||||
Pluf_Log::error(array('IDF_Plugin_Git_Serve::initRepository', $res, $fullpath));
|
||||
throw new Exception(sprintf('Init repository error, exit status %d.', $res));
|
||||
}
|
||||
Pluf_Log::event(array('IDF_Plugin_Git_Serve::initRepository', 'success', $fullpath));
|
||||
// Add the post-update hook by removing the original one and add the
|
||||
// Indefero's one.
|
||||
$p = realpath(dirname(__FILE__).'/../../../../scripts/git-post-update');
|
||||
$p = Pluf::f('idf_plugin_syncgit_post_update', $p);
|
||||
if (!@unlink($fullpath.'/hooks/post-update')) {
|
||||
Pluf_Log::warn(array('IDF_Plugin_Git_Serve::initRepository',
|
||||
'post-update hook removal error.',
|
||||
$fullpath.'/hooks/post-update'));
|
||||
return;
|
||||
}
|
||||
exec(sprintf(Pluf::f('idf_exec_cmd_prefix', '').'ln -s %s %s',
|
||||
escapeshellarg($p),
|
||||
escapeshellarg($fullpath.'/hooks/post-update')),
|
||||
$out, $res);
|
||||
if ($res != 0) {
|
||||
Pluf_Log::warn(array('IDF_Plugin_Git_Serve::initRepository',
|
||||
'post-update hook creation error.',
|
||||
$fullpath.'/hooks/post-update'));
|
||||
return;
|
||||
}
|
||||
Pluf_Log::debug(array('IDF_Plugin_Git_Serve::initRepository',
|
||||
'Added post-update hook.', $fullpath));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +238,7 @@ class IDF_Plugin_SyncGit_Serve
|
||||
{
|
||||
$sql = new Pluf_SQL('shortname=%s', array($relpath));
|
||||
$projects = Pluf::factory('IDF_Project')->getList(array('filter'=>$sql->gen()));
|
||||
if ($projects->count() != 1) {
|
||||
if ($projects->count() != 1 and file_exists($fullpath)) {
|
||||
return $this->gitExportDeny($fullpath);
|
||||
}
|
||||
$project = $projects[0];
|
||||
@@ -217,7 +246,8 @@ class IDF_Plugin_SyncGit_Serve
|
||||
$conf->setProject($project);
|
||||
$scm = $conf->getVal('scm', 'git');
|
||||
if ($scm == 'git' and !file_exists($fullpath)) {
|
||||
$this->initRepository($fullpath);
|
||||
// No repository yet, just skip
|
||||
return false;
|
||||
}
|
||||
if ($scm != 'git' or $project->private) {
|
||||
return $this->gitExportDeny($fullpath);
|
||||
|
@@ -51,6 +51,9 @@ class IDF_Plugin_SyncMercurial
|
||||
case 'Pluf_User::passwordUpdated':
|
||||
$plug->processSyncPasswd($params['user']);
|
||||
break;
|
||||
case 'hgchangegroup.php::run':
|
||||
$plug->processSyncTimeline($params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +100,8 @@ class IDF_Plugin_SyncMercurial
|
||||
}
|
||||
$ht = new File_Passwd_Authbasic($passwd_file);
|
||||
$ht->load();
|
||||
$ht->setMode(FILE_PASSWD_SHA);
|
||||
$ht->setMode(Pluf::f('idf_plugin_syncmercurial_passwd_mode',
|
||||
FILE_PASSWD_SHA));
|
||||
if ($ht->userExists($user->login)) {
|
||||
$ht->changePasswd($user->login, $this->getMercurialPass($user));
|
||||
} else {
|
||||
@@ -138,7 +142,8 @@ class IDF_Plugin_SyncMercurial
|
||||
throw new Exception (sprintf(__('%s does not exist or is not writable.'), $passwd_file));
|
||||
}
|
||||
$ht = new File_Passwd_Authbasic($passwd_file);
|
||||
$ht->setMode(FILE_PASSWD_SHA);
|
||||
$ht->setMode(Pluf::f('idf_plugin_syncmercurial_passwd_mode',
|
||||
FILE_PASSWD_SHA));
|
||||
$ht->load();
|
||||
$mem = $project->getMembershipData();
|
||||
$members = array_merge((array)$mem['members'], (array)$mem['owners'],
|
||||
@@ -220,4 +225,25 @@ class IDF_Plugin_SyncMercurial
|
||||
file_put_contents($notify_file, ' ', LOCK_EX);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the timeline in post commit.
|
||||
*
|
||||
*/
|
||||
public function processSyncTimeline($params)
|
||||
{
|
||||
$pname = basename($params['rel_dir']);
|
||||
try {
|
||||
$project = IDF_Project::getOr404($pname);
|
||||
} catch (Pluf_HTTP_Error404 $e) {
|
||||
Pluf_Log::event(array('IDF_Plugin_SyncMercurial::processSyncTimeline', 'Project not found.', array($pname, $params)));
|
||||
return false; // Project not found
|
||||
}
|
||||
// Now we have the project and can update the timeline
|
||||
Pluf_Log::debug(array('IDF_Plugin_SyncMercurial::processSyncTimeline', 'Project found', $pname, $project->id));
|
||||
IDF_Scm::syncTimeline($project, true);
|
||||
Pluf_Log::event(array('IDF_Plugin_SyncMercurial::processSyncTimeline', 'sync', array($pname, $project->id)));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ class IDF_Plugin_SyncSvn
|
||||
// First check for the 3 mandatory config variables.
|
||||
if (!Pluf::f('idf_plugin_syncsvn_authz_file', false) or
|
||||
!Pluf::f('idf_plugin_syncsvn_passwd_file', false) or
|
||||
!Pluf::f('idf_plugin_syncsvn_svn_path'. false)) {
|
||||
!Pluf::f('idf_plugin_syncsvn_svn_path', false)) {
|
||||
return;
|
||||
}
|
||||
include_once 'File/Passwd/Authdigest.php'; // $ pear install File_Passwd
|
||||
@@ -52,6 +52,12 @@ class IDF_Plugin_SyncSvn
|
||||
case 'Pluf_User::passwordUpdated':
|
||||
$plug->processSyncPasswd($params['user']);
|
||||
break;
|
||||
case 'IDF_Project::preDelete':
|
||||
$plug->processSvnDelete($params['project']);
|
||||
break;
|
||||
case 'svnpostcommit.php::run':
|
||||
$plug->processSvnUpdateTimeline($params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +89,31 @@ class IDF_Plugin_SyncSvn
|
||||
$ll = exec($cmd, $output, $return);
|
||||
return ($return == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the project from the drive and update the access rights.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return bool Success
|
||||
*/
|
||||
function processSvnDelete($project)
|
||||
{
|
||||
if (!Pluf::f('idf_plugin_syncsvn_remove_orphans', false)) {
|
||||
return;
|
||||
}
|
||||
if ($project->getConf()->getVal('scm') != 'svn') {
|
||||
return false;
|
||||
}
|
||||
$this->SyncAccess($project); // exclude $project
|
||||
$shortname = $project->shortname;
|
||||
if (false===($svn_path=Pluf::f('idf_plugin_syncsvn_svn_path',false))) {
|
||||
throw new Pluf_Exception_SettingError("'idf_plugin_syncsvn_svn_path' must be defined in your configuration file.");
|
||||
}
|
||||
if (file_exists($svn_path.'/'.$shortname)) {
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').'rm -rf '.$svn_path.'/'.$shortname;
|
||||
exec($cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronise an user's password.
|
||||
@@ -156,8 +187,10 @@ class IDF_Plugin_SyncSvn
|
||||
* We rebuild the complete file each time. This is just to be sure
|
||||
* not to bork the rights when trying to just edit part of the
|
||||
* file.
|
||||
*
|
||||
* @param IDF_Project Possibly exclude a project (null)
|
||||
*/
|
||||
function SyncAccess()
|
||||
function SyncAccess($exclude=null)
|
||||
{
|
||||
$authz_file = Pluf::f('idf_plugin_syncsvn_authz_file');
|
||||
$access_owners = Pluf::f('idf_plugin_syncsvn_access_owners', 'rw');
|
||||
@@ -170,6 +203,9 @@ class IDF_Plugin_SyncSvn
|
||||
}
|
||||
$fcontent = '';
|
||||
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
|
||||
if ($exclude and $exclude->id == $project->id) {
|
||||
continue;
|
||||
}
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($project);
|
||||
if ($conf->getVal('scm') != 'svn' or
|
||||
@@ -199,4 +235,25 @@ class IDF_Plugin_SyncSvn
|
||||
file_put_contents($authz_file, $fcontent, LOCK_EX);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the timeline in post commit.
|
||||
*
|
||||
*/
|
||||
public function processSvnUpdateTimeline($params)
|
||||
{
|
||||
$pname = basename($params['repo_dir']);
|
||||
try {
|
||||
$project = IDF_Project::getOr404($pname);
|
||||
} catch (Pluf_HTTP_Error404 $e) {
|
||||
Pluf_Log::event(array('IDF_Plugin_SyncSvn::processSvnUpdateTimeline', 'Project not found.', array($pname, $params)));
|
||||
return false; // Project not found
|
||||
}
|
||||
// Now we have the project and can update the timeline
|
||||
Pluf_Log::debug(array('IDF_Plugin_SyncGit::processSvnUpdateTimeline', 'Project found', $pname, $project->id));
|
||||
IDF_Scm::syncTimeline($project, true);
|
||||
Pluf_Log::event(array('IDF_Plugin_SyncGit::processSvnUpdateTimeline', 'sync', array($pname, $project->id)));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -230,7 +230,7 @@ class IDF_Precondition
|
||||
return true; // no match in the hash, anonymous
|
||||
}
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
list($userid, $projectid) = split(':', $cr->decrypt($encrypted), 2);
|
||||
list($userid, $projectid) = explode(':', $cr->decrypt($encrypted), 2);
|
||||
if ($projectid != $request->project->id) {
|
||||
return true; // anonymous
|
||||
}
|
||||
|
@@ -32,6 +32,14 @@ class IDF_Project extends Pluf_Model
|
||||
public $_model = __CLASS__;
|
||||
public $_extra_cache = array();
|
||||
protected $_pconf = null;
|
||||
/**
|
||||
* Check if the project as one restricted tab.
|
||||
*
|
||||
* This is the cached information.
|
||||
*
|
||||
* @see self::isRestricted
|
||||
*/
|
||||
protected $_isRestricted = null;
|
||||
|
||||
function init()
|
||||
{
|
||||
@@ -210,9 +218,9 @@ class IDF_Project extends Pluf_Model
|
||||
$conf = $this->getConf();
|
||||
$tags = array();
|
||||
foreach (preg_split("/\015\012|\015|\012/", $conf->getVal($cfg_key, $default), -1, PREG_SPLIT_NO_EMPTY) as $s) {
|
||||
$_s = split('=', $s, 2);
|
||||
$_s = explode('=', $s, 2);
|
||||
$v = trim($_s[0]);
|
||||
$_v = split(':', $v, 2);
|
||||
$_v = explode(':', $v, 2);
|
||||
if (count($_v) > 1) {
|
||||
$class = trim($_v[0]);
|
||||
$name = trim($_v[1]);
|
||||
@@ -349,15 +357,53 @@ class IDF_Project extends Pluf_Model
|
||||
return new Pluf_Template_ContextVars($tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the repository size.
|
||||
*
|
||||
* @param bool Force to skip the cache (false)
|
||||
* @return int Size in byte or -1 if not available
|
||||
*/
|
||||
public function getRepositorySize($force=false)
|
||||
{
|
||||
$last_eval = $this->getConf()->getVal('repository_size_check_date', 0);
|
||||
if (!$force and $last_eval > time()-86400) {
|
||||
return $this->getConf()->getVal('repository_size', -1);
|
||||
}
|
||||
$scm = IDF_Scm::get($this);
|
||||
$this->getConf()->setVal('repository_size', $scm->getRepositorySize());
|
||||
$this->getConf()->setVal('repository_size_check_date', time());
|
||||
return $this->getConf()->getVal('repository_size', -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access url to the repository.
|
||||
*
|
||||
* This will return the right url based on the user.
|
||||
*
|
||||
* @param Pluf_User The user (null)
|
||||
*/
|
||||
public function getSourceAccessUrl($user=null)
|
||||
{
|
||||
$right = $this->getConf()->getVal('source_access_rights', 'all');
|
||||
if (($user == null or $user->isAnonymous())
|
||||
and $right == 'all' and !$this->private) {
|
||||
return $this->getRemoteAccessUrl();
|
||||
}
|
||||
return $this->getWriteRemoteAccessUrl($user);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the remote access url to the repository.
|
||||
*
|
||||
* This will always return the anonymous access url.
|
||||
*/
|
||||
public function getRemoteAccessUrl()
|
||||
{
|
||||
$conf = $this->getConf();
|
||||
$scm = $conf->getVal('scm', 'git');
|
||||
$scms = Pluf::f('allowed_scm');
|
||||
Pluf::loadClass($scms[$scm]);
|
||||
return call_user_func(array($scms[$scm], 'getAnonymousAccessUrl'),
|
||||
$this);
|
||||
}
|
||||
@@ -548,6 +594,28 @@ class IDF_Project extends Pluf_Model
|
||||
*/
|
||||
public function preDelete()
|
||||
{
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Project::preDelete
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Project
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform special
|
||||
* operations at the deletion of a project.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('project' => $project)
|
||||
*
|
||||
*/
|
||||
$params = array('project' => $this);
|
||||
Pluf_Signal::send('IDF_Project::preDelete',
|
||||
'IDF_Project', $params);
|
||||
$what = array('IDF_Upload', 'IDF_Review', 'IDF_Issue',
|
||||
'IDF_WikiPage', 'IDF_Commit',
|
||||
);
|
||||
@@ -557,4 +625,37 @@ class IDF_Project extends Pluf_Model
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the project has one restricted tab.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRestricted()
|
||||
{
|
||||
if ($this->_isRestricted !== null) {
|
||||
return $this->_isRestricted;
|
||||
}
|
||||
if ($this->private) {
|
||||
$this->_isRestricted = true;
|
||||
return true;
|
||||
}
|
||||
$tabs = array(
|
||||
'source_access_rights',
|
||||
'issues_access_rights',
|
||||
'downloads_access_rights',
|
||||
'wiki_access_rights',
|
||||
'review_access_rights'
|
||||
);
|
||||
$conf = $this->getConf();
|
||||
foreach ($tabs as $tab) {
|
||||
if (!in_array($conf->getVal($tab, 'all'),
|
||||
array('all', 'none'))) {
|
||||
$this->_isRestricted = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
$this->_isRestricted = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -32,6 +32,15 @@ Pluf::loadFunction('Pluf_Template_dateAgo');
|
||||
*
|
||||
* The real content of the review is in the IDF_Review_Patch which
|
||||
* contains a given patch and associated comments from reviewers.
|
||||
*
|
||||
* Basically the hierarchy of the models is:
|
||||
* - Review > Patch > Comment > Comment on file
|
||||
*
|
||||
* For each review, one can have several patches. Each patch, is
|
||||
* getting a series of comments. A comment is tracking the state
|
||||
* change in the review (like the issue comments). For each comment,
|
||||
* we have a series of file comments. The file comments are associated
|
||||
* to the a given modified file in the patch.
|
||||
*/
|
||||
class IDF_Review extends Pluf_Model
|
||||
{
|
||||
@@ -71,12 +80,12 @@ class IDF_Review extends Pluf_Model
|
||||
'verbose' => __('submitter'),
|
||||
'relate_name' => 'submitted_review',
|
||||
),
|
||||
'reviewers' =>
|
||||
'interested' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Manytomany',
|
||||
'model' => 'Pluf_User',
|
||||
'blank' => true,
|
||||
'help_text' => 'Reviewers will get an email notification when the review is changed.',
|
||||
'help_text' => 'Interested users will get an email notification when the review is changed.',
|
||||
),
|
||||
'tags' =>
|
||||
array(
|
||||
@@ -117,11 +126,25 @@ class IDF_Review extends Pluf_Model
|
||||
'join_tags' =>
|
||||
array(
|
||||
'join' => 'LEFT JOIN '.$table
|
||||
.' ON idf_issue_id=id',
|
||||
.' ON idf_review_id=id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through the patches and comments to get the reviewers.
|
||||
*/
|
||||
function getReviewers()
|
||||
{
|
||||
$rev = new ArrayObject();
|
||||
foreach ($this->get_patches_list() as $p) {
|
||||
foreach ($p->get_comments_list() as $c) {
|
||||
$rev[] = $c->get_submitter();
|
||||
}
|
||||
}
|
||||
return Pluf_Model_RemoveDuplicates($rev);
|
||||
}
|
||||
|
||||
function __toString()
|
||||
{
|
||||
return $this->id.' - '.$this->summary;
|
||||
@@ -140,7 +163,7 @@ class IDF_Review extends Pluf_Model
|
||||
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
if ($create) {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
$this->modif_dtime = gmdate('Y-m-d H:i:s');
|
||||
@@ -148,6 +171,8 @@ class IDF_Review extends Pluf_Model
|
||||
|
||||
function postSave($create=false)
|
||||
{
|
||||
// At creation, we index after saving the associated patch.
|
||||
if (!$create) IDF_Search::index($this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
224
src/IDF/Review/Comment.php
Normal file
224
src/IDF/Review/Comment.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* A comment set on a review.
|
||||
*
|
||||
* A comment is associated to a patch as a review can have many
|
||||
* patches associated to it.
|
||||
*
|
||||
* A comment is also tracking the changes in the review in the same
|
||||
* way the issue comment is tracking the changes in the issue.
|
||||
*
|
||||
*
|
||||
*/
|
||||
class IDF_Review_Comment extends Pluf_Model
|
||||
{
|
||||
public $_model = __CLASS__;
|
||||
|
||||
function init()
|
||||
{
|
||||
$this->_a['table'] = 'idf_review_comments';
|
||||
$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,
|
||||
),
|
||||
'patch' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'IDF_Review_Patch',
|
||||
'blank' => false,
|
||||
'verbose' => __('patch'),
|
||||
'relate_name' => 'comments',
|
||||
),
|
||||
'content' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Text',
|
||||
'blank' => true, // if only commented on lines
|
||||
'verbose' => __('comment'),
|
||||
),
|
||||
'submitter' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'Pluf_User',
|
||||
'blank' => false,
|
||||
'verbose' => __('submitter'),
|
||||
),
|
||||
'changes' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Serialized',
|
||||
'blank' => true,
|
||||
'verbose' => __('changes'),
|
||||
'help_text' => 'Serialized array of the changes in the review.',
|
||||
),
|
||||
'vote' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Integer',
|
||||
'default' => 0,
|
||||
'blank' => true,
|
||||
'verbose' => __('vote'),
|
||||
'help_text' => '1, 0 or -1 for positive, neutral or negative vote.',
|
||||
),
|
||||
'creation_dtime' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Datetime',
|
||||
'blank' => true,
|
||||
'verbose' => __('creation date'),
|
||||
'index' => true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function changedReview()
|
||||
{
|
||||
return (is_array($this->changes) and count($this->changes) > 0);
|
||||
}
|
||||
|
||||
function _toIndex()
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
function preDelete()
|
||||
{
|
||||
IDF_Timeline::remove($this);
|
||||
}
|
||||
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($create) {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
|
||||
function postSave($create=false)
|
||||
{
|
||||
if ($create) {
|
||||
IDF_Timeline::insert($this,
|
||||
$this->get_patch()->get_review()->get_project(),
|
||||
$this->get_submitter());
|
||||
}
|
||||
}
|
||||
|
||||
public function timelineFragment($request)
|
||||
{
|
||||
$review = $this->get_patch()->get_review();
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
|
||||
array($request->project->shortname,
|
||||
$review->id));
|
||||
$out = '<tr class="log"><td><a href="'.$url.'">'.
|
||||
Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
|
||||
'</a></td><td>';
|
||||
$stag = new IDF_Template_ShowUser();
|
||||
$user = $stag->start($this->get_submitter(), $request, '', false);
|
||||
$ic = (in_array($review->status, $request->project->getTagIdsByStatus('closed'))) ? 'issue-c' : 'issue-o';
|
||||
$out .= sprintf(__('<a href="%1$s" class="%2$s" title="View review">Review %3$d</a>, %4$s'), $url, $ic, $review->id, Pluf_esc($review->summary)).'</td>';
|
||||
$out .= "\n".'<tr class="extra"><td colspan="2">
|
||||
<div class="helptext right">'.sprintf(__('Update of <a href="%s" class="%s">review %d</a>, by %s'), $url, $ic, $review->id, $user).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
|
||||
public function feedFragment($request)
|
||||
{
|
||||
$review = $this->get_patch()->get_review();
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
|
||||
array($request->project->shortname,
|
||||
$review->id));
|
||||
$title = sprintf(__('%s: Updated review %d - %s'),
|
||||
Pluf_esc($request->project->name),
|
||||
$review->id, Pluf_esc($review->summary));
|
||||
$url .= '#ic'.$this->id;
|
||||
$date = Pluf_Date::gmDateToGmString($this->creation_dtime);
|
||||
$context = new Pluf_Template_Context_Request(
|
||||
$request,
|
||||
array('url' => $url,
|
||||
'author' => $this->get_submitter(),
|
||||
'title' => $title,
|
||||
'c' => $this,
|
||||
'review' => $review,
|
||||
'date' => $date)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/review/feedfragment.xml');
|
||||
return $tmpl->render($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify of the update of the review.
|
||||
*
|
||||
*
|
||||
* @param IDF_Conf Current configuration
|
||||
* @param bool Creation (true)
|
||||
*/
|
||||
public function notify($conf, $create=true)
|
||||
{
|
||||
$patch = $this->get_patch();
|
||||
$review = $patch->get_review();
|
||||
$prj = $review->get_project();
|
||||
$to_email = array();
|
||||
if ('' != $conf->getVal('review_notification_email', '')) {
|
||||
$langs = Pluf::f('languages', array('en'));
|
||||
$to_email[] = array($conf->getVal('issues_notification_email'),
|
||||
$langs[0]);
|
||||
}
|
||||
$current_locale = Pluf_Translation::getLocale();
|
||||
$reviewers = $review->getReviewers();
|
||||
if (!Pluf_Model_InArray($review->get_submitter(), $reviewers)) {
|
||||
$reviewers[] = $review->get_submitter();
|
||||
}
|
||||
$comments = $patch->getFileComments(array('order' => 'id DESC'));
|
||||
$gcomments = $patch->get_comments_list(array('order' => 'id DESC'));
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'review' => $review,
|
||||
'patch' => $patch,
|
||||
'comments' => $comments,
|
||||
'gcomments' => $gcomments,
|
||||
'project' => $prj,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
// build the list of emails and lang
|
||||
foreach ($reviewers as $user) {
|
||||
$email_lang = array($user->email,
|
||||
$user->language);
|
||||
if (!in_array($email_lang, $to_email)) {
|
||||
$to_email[] = $email_lang;
|
||||
}
|
||||
}
|
||||
$tmpl = new Pluf_Template('idf/review/review-updated-email.txt');
|
||||
foreach ($to_email as $email_lang) {
|
||||
Pluf_Translation::loadSetLocale($email_lang[1]);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $email_lang[0],
|
||||
sprintf(__('Updated Code Review %s - %s (%s)'),
|
||||
$review->id, $review->summary, $prj->shortname));
|
||||
|
||||
$email->addTextMessage($tmpl->render($context));
|
||||
$email->sendMail();
|
||||
}
|
||||
Pluf_Translation::loadSetLocale($current_locale);
|
||||
}
|
||||
}
|
@@ -40,13 +40,13 @@ class IDF_Review_FileComment extends Pluf_Model
|
||||
'type' => 'Pluf_DB_Field_Sequence',
|
||||
'blank' => true,
|
||||
),
|
||||
'patch' =>
|
||||
'comment' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'IDF_Review_Patch',
|
||||
'model' => 'IDF_Review_Comment',
|
||||
'blank' => false,
|
||||
'verbose' => __('patch'),
|
||||
'relate_name' => 'filecomments',
|
||||
'verbose' => __('comment'),
|
||||
),
|
||||
'cfile' =>
|
||||
array(
|
||||
@@ -55,32 +55,25 @@ class IDF_Review_FileComment extends Pluf_Model
|
||||
'size' => 250,
|
||||
'help_text' => 'The changed file, for example src/foo/bar.txt, this is the path to access it in the repository.',
|
||||
),
|
||||
'cline' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Integer',
|
||||
'blank' => false,
|
||||
'default' => 0,
|
||||
'help_text' => 'The commented line, negative value is the old file, positive the new, 0 general comment.',
|
||||
),
|
||||
'content' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Text',
|
||||
'blank' => false,
|
||||
'verbose' => __('comment'),
|
||||
),
|
||||
'submitter' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'Pluf_User',
|
||||
'blank' => false,
|
||||
'verbose' => __('submitter'),
|
||||
'relate_name' => 'commented_patched_files',
|
||||
),
|
||||
'creation_dtime' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Datetime',
|
||||
'blank' => true,
|
||||
'verbose' => __('creation date'),
|
||||
),
|
||||
);
|
||||
$this->_a['idx'] = array(
|
||||
'creation_dtime_idx' =>
|
||||
array(
|
||||
'col' => 'creation_dtime',
|
||||
'type' => 'normal',
|
||||
'index' => true,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -92,12 +85,11 @@ class IDF_Review_FileComment extends Pluf_Model
|
||||
|
||||
function preDelete()
|
||||
{
|
||||
IDF_Timeline::remove($this);
|
||||
}
|
||||
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
if ($create) {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,10 @@
|
||||
/**
|
||||
* A patch to be reviewed.
|
||||
*
|
||||
* A patch can be marked as being directly the commit, in that case
|
||||
* the patch does not store the diff file as it can be retrieved from
|
||||
* the backend.
|
||||
*
|
||||
*/
|
||||
class IDF_Review_Patch extends Pluf_Model
|
||||
{
|
||||
@@ -81,15 +85,28 @@ class IDF_Review_Patch extends Pluf_Model
|
||||
'type' => 'Pluf_DB_Field_Datetime',
|
||||
'blank' => true,
|
||||
'verbose' => __('creation date'),
|
||||
'index' => true,
|
||||
),
|
||||
);
|
||||
$this->_a['idx'] = array(
|
||||
'creation_dtime_idx' =>
|
||||
array(
|
||||
'col' => 'creation_dtime',
|
||||
'type' => 'normal',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of file comments.
|
||||
*
|
||||
* It will go through the patch comments and find for each the
|
||||
* file comments.
|
||||
*
|
||||
* @param array Filter to apply to the file comment list (array())
|
||||
*/
|
||||
function getFileComments($filter=array())
|
||||
{
|
||||
$files = new ArrayObject();
|
||||
foreach ($this->get_comments_list(array('order'=>'creation_dtime ASC')) as $ct) {
|
||||
foreach ($ct->get_filecomments_list($filter) as $fc) {
|
||||
$files[] = $fc;
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
function _toIndex()
|
||||
@@ -99,25 +116,95 @@ class IDF_Review_Patch extends Pluf_Model
|
||||
|
||||
function preDelete()
|
||||
{
|
||||
IDF_Timeline::remove($this);
|
||||
}
|
||||
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
if ($create) {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
|
||||
function postSave($create=false)
|
||||
{
|
||||
if ($create) {
|
||||
IDF_Timeline::insert($this,
|
||||
$this->get_review()->get_project(),
|
||||
$this->get_review()->get_submitter());
|
||||
IDF_Search::index($this->get_review());
|
||||
}
|
||||
}
|
||||
|
||||
public function timelineFragment($request)
|
||||
{
|
||||
$review = $this->get_review();
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
|
||||
array($request->project->shortname,
|
||||
$review->id));
|
||||
$out = '<tr class="log"><td><a href="'.$url.'">'.
|
||||
Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
|
||||
'</a></td><td>';
|
||||
$stag = new IDF_Template_ShowUser();
|
||||
$user = $stag->start($review->get_submitter(), $request, '', false);
|
||||
$ic = (in_array($review->status, $request->project->getTagIdsByStatus('closed'))) ? 'issue-c' : 'issue-o';
|
||||
$out .= sprintf(__('<a href="%1$s" class="%2$s" title="View review">Review %3$d</a>, %4$s'), $url, $ic, $review->id, Pluf_esc($review->summary)).'</td>';
|
||||
$out .= "\n".'<tr class="extra"><td colspan="2">
|
||||
<div class="helptext right">'.sprintf(__('Creation of <a href="%s" class="%s">review %d</a>, by %s'), $url, $ic, $review->id, $user).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
|
||||
public function feedFragment($request)
|
||||
{
|
||||
return '';
|
||||
$review = $this->get_review();
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
|
||||
array($request->project->shortname,
|
||||
$review->id));
|
||||
$title = sprintf(__('%s: Creation of Review %d - %s'),
|
||||
Pluf_esc($request->project->name),
|
||||
$review->id, Pluf_esc($review->summary));
|
||||
$date = Pluf_Date::gmDateToGmString($this->creation_dtime);
|
||||
$context = new Pluf_Template_Context_Request(
|
||||
$request,
|
||||
array('url' => $url,
|
||||
'author' => $review->get_submitter(),
|
||||
'title' => $title,
|
||||
'p' => $this,
|
||||
'review' => $review,
|
||||
'date' => $date)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/review/feedfragment.xml');
|
||||
return $tmpl->render($context);
|
||||
}
|
||||
|
||||
public function notify($conf, $create=true)
|
||||
{
|
||||
if ('' == $conf->getVal('review_notification_email', '')) {
|
||||
return;
|
||||
}
|
||||
$current_locale = Pluf_Translation::getLocale();
|
||||
$langs = Pluf::f('languages', array('en'));
|
||||
Pluf_Translation::loadSetLocale($langs[0]);
|
||||
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'review' => $this->get_review(),
|
||||
'patch' => $this,
|
||||
'comments' => array(),
|
||||
'project' => $this->get_review()->get_project(),
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/review/review-created-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'),
|
||||
$conf->getVal('review_notification_email'),
|
||||
sprintf(__('New Code Review %s - %s (%s)'),
|
||||
$this->get_review()->id,
|
||||
$this->get_review()->summary,
|
||||
$this->get_review()->get_project()->shortname));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
Pluf_Translation::loadSetLocale($current_locale);
|
||||
}
|
||||
}
|
||||
|
@@ -71,14 +71,6 @@ class IDF_Scm
|
||||
*/
|
||||
protected $cache = array();
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public function __construct($repo, $project=null)
|
||||
{
|
||||
$this->repo = $repo;
|
||||
$this->project = $project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the correct scm backend object.
|
||||
@@ -95,6 +87,52 @@ class IDF_Scm
|
||||
return call_user_func(array($scms[$scm], 'factory'), $project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run exec and log some information.
|
||||
*
|
||||
* @param $caller Calling method
|
||||
* @param $cmd Command to run
|
||||
* @param &$out Array of output
|
||||
* @param &$return Return value
|
||||
* @return string Last line of the command
|
||||
*/
|
||||
public static function exec($caller, $cmd, &$out=null, &$return=null)
|
||||
{
|
||||
Pluf_Log::stime('timer');
|
||||
$ret = exec($cmd, $out, $return);
|
||||
Pluf_Log::perf(array($caller, $cmd, Pluf_Log::etime('timer', 'total_exec')));
|
||||
Pluf_Log::debug(array($caller, $cmd, $out));
|
||||
Pluf_Log::inc('exec_calls');
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run shell_exec and log some information.
|
||||
*
|
||||
* @param $caller Calling method
|
||||
* @param $cmd Command to run
|
||||
* @return string The output
|
||||
*/
|
||||
public static function shell_exec($caller, $cmd)
|
||||
{
|
||||
Pluf_Log::stime('timer');
|
||||
$ret = shell_exec($cmd);
|
||||
Pluf_Log::perf(array($caller, $cmd, Pluf_Log::etime('timer', 'total_exec')));
|
||||
Pluf_Log::debug(array($caller, $cmd, $ret));
|
||||
Pluf_Log::inc('exec_calls');
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the repository in bytes.
|
||||
*
|
||||
* @return int Size in byte, -1 if the size cannot be evaluated.
|
||||
*/
|
||||
public function getRepositorySize()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of the git daemon.
|
||||
*
|
||||
@@ -200,6 +238,24 @@ class IDF_Scm
|
||||
throw new Pluf_Exception_NotImplemented();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns in which tags a commit/path is.
|
||||
*
|
||||
* A commit can be in several tags and some of the SCMs are
|
||||
* managing tags using subfolders (like Subversion).
|
||||
*
|
||||
* This means that to know in which tag we are at the moment,
|
||||
* one needs to have both the path and the commit.
|
||||
*
|
||||
* @param string Commit
|
||||
* @param string Path
|
||||
* @return array Tags
|
||||
*/
|
||||
public function inTags($commit, $path)
|
||||
{
|
||||
throw new Pluf_Exception_NotImplemented();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the main branch.
|
||||
*
|
||||
@@ -337,19 +393,27 @@ class IDF_Scm
|
||||
* Sync the changes in the repository with the timeline.
|
||||
*
|
||||
*/
|
||||
public static function syncTimeline($project)
|
||||
public static function syncTimeline($project, $force=false)
|
||||
{
|
||||
$cache = Pluf_Cache::factory();
|
||||
$key = 'IDF_Scm:'.$project->shortname.':lastsync';
|
||||
if (null === ($res=$cache->get($key))) {
|
||||
if ($force or null === ($res=$cache->get($key))) {
|
||||
$scm = IDF_Scm::get($project);
|
||||
foreach ($scm->getBranches() as $branche) {
|
||||
foreach ($scm->getChangeLog($branche, 25) as $change) {
|
||||
if ($scm->isAvailable()) {
|
||||
foreach ($scm->getChangeLog($scm->getMainBranch(), 25) as $change) {
|
||||
IDF_Commit::getOrAdd($change, $project);
|
||||
}
|
||||
$cache->set($key, true, (int)(Pluf::f('cache_timeout', 300)/2));
|
||||
}
|
||||
$cache->set($key, true, (int)(Pluf::f('cache_timeout', 300)/2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path, encode everything but the /
|
||||
*/
|
||||
public static function smartEncode($path)
|
||||
{
|
||||
return str_replace('%2F', '/', rawurlencode($path));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -54,6 +54,7 @@ class IDF_Scm_Cache_Git extends Pluf_Model
|
||||
$cache = new IDF_Scm_Cache_Git();
|
||||
$cache->project = $this->_project;
|
||||
$cache->githash = $blob->hash;
|
||||
$blob->title = IDF_Commit::toUTF8($blob->title);
|
||||
$cache->content = $blob->date.chr(31).$blob->author.chr(31).$blob->title;
|
||||
$sql = new Pluf_SQL('project=%s AND githash=%s',
|
||||
array($this->_project->id, $blob->hash));
|
||||
@@ -83,7 +84,7 @@ class IDF_Scm_Cache_Git extends Pluf_Model
|
||||
$sql = new Pluf_SQL('project=%s AND githash IN ('.implode(', ', $hashes).')',
|
||||
array($this->_project->id));
|
||||
foreach (Pluf::factory(__CLASS__)->getList(array('filter' => $sql->gen())) as $blob) {
|
||||
$tmp = split(chr(31), $blob->content, 3);
|
||||
$tmp = explode(chr(31), $blob->content, 3);
|
||||
|
||||
$res[$blob->githash] = (object) array(
|
||||
'hash' => $blob->githash,
|
||||
|
@@ -35,14 +35,33 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
* *
|
||||
* ============================================== */
|
||||
|
||||
public function __construct($repo, $project=null)
|
||||
{
|
||||
$this->repo = $repo;
|
||||
$this->project = $project;
|
||||
}
|
||||
|
||||
public function getRepositorySize()
|
||||
{
|
||||
if (!file_exists($this->repo)) {
|
||||
return 0;
|
||||
}
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').'du -sk '
|
||||
.escapeshellarg($this->repo);
|
||||
$out = explode(' ',
|
||||
self::shell_exec('IDF_Scm_Git::getRepositorySize', $cmd),
|
||||
2);
|
||||
return (int) $out[0]*1024;
|
||||
}
|
||||
|
||||
public function isAvailable()
|
||||
{
|
||||
try {
|
||||
$this->getBranches();
|
||||
$branches = $this->getBranches();
|
||||
} catch (IDF_Scm_Exception $e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return (count($branches) > 0);
|
||||
}
|
||||
|
||||
public function getBranches()
|
||||
@@ -53,7 +72,8 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '')
|
||||
.sprintf('GIT_DIR=%s '.Pluf::f('git_path', 'git').' branch',
|
||||
escapeshellarg($this->repo));
|
||||
exec($cmd, $out, $return);
|
||||
self::exec('IDF_Scm_Git::getBranches',
|
||||
$cmd, $out, $return);
|
||||
if ($return != 0) {
|
||||
throw new IDF_Scm_Exception(sprintf($this->error_tpl,
|
||||
$cmd, $return,
|
||||
@@ -61,7 +81,12 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
}
|
||||
$res = array();
|
||||
foreach ($out as $b) {
|
||||
$res[substr($b, 2)] = '';
|
||||
$b = substr($b, 2);
|
||||
if (false !== strpos($b, '/')) {
|
||||
$res[$this->getCommit($b)->commit] = $b;
|
||||
} else {
|
||||
$res[$b] = '';
|
||||
}
|
||||
}
|
||||
$this->cache['branches'] = $res;
|
||||
return $res;
|
||||
@@ -69,14 +94,15 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
|
||||
public function getMainBranch()
|
||||
{
|
||||
$possible = array('master', 'main', 'trunk', 'local');
|
||||
$branches = array_keys($this->getBranches());
|
||||
foreach ($possible as $p) {
|
||||
if (in_array($p, $branches)) {
|
||||
return $p;
|
||||
}
|
||||
$branches = $this->getBranches();
|
||||
if (array_key_exists('master', $branches))
|
||||
return 'master';
|
||||
static $possible = array('main', 'trunk', 'local');
|
||||
for ($i = 0; 3 > $i; ++$i) {
|
||||
if (array_key_exists($possible[$i], $branches))
|
||||
return $possible[$i];
|
||||
}
|
||||
return $branches[0];
|
||||
return key($branches);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,10 +113,74 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
*/
|
||||
public function inBranches($commit, $path)
|
||||
{
|
||||
return (in_array($commit, array_keys($this->getBranches())))
|
||||
? array($commit) : array();
|
||||
return $this->_inObject($commit, 'branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IDF_Scm::getTags()
|
||||
**/
|
||||
public function getTags()
|
||||
{
|
||||
if (isset($this->cache['tags'])) {
|
||||
return $this->cache['tags'];
|
||||
}
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '')
|
||||
.sprintf('GIT_DIR=%s %s tag',
|
||||
escapeshellarg($this->repo),
|
||||
Pluf::f('git_path', 'git'));
|
||||
self::exec('IDF_Scm_Git::getTags', $cmd, $out, $return);
|
||||
if (0 != $return) {
|
||||
throw new IDF_Scm_Exception(sprintf($this->error_tpl,
|
||||
$cmd, $return,
|
||||
implode("\n", $out)));
|
||||
}
|
||||
$res = array();
|
||||
foreach ($out as $b) {
|
||||
if (false !== strpos($b, '/')) {
|
||||
$res[$this->getCommit($b)->commit] = $b;
|
||||
} else {
|
||||
$res[$b] = '';
|
||||
}
|
||||
}
|
||||
$this->cache['tags'] = $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IDF_Scm::inTags()
|
||||
**/
|
||||
public function inTags($commit, $path)
|
||||
{
|
||||
return $this->_inObject($commit, 'tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns in which branches or tags a commit is.
|
||||
*
|
||||
* @param string Commit
|
||||
* @param string Object's type: 'branch' or 'tag'.
|
||||
* @return array
|
||||
*/
|
||||
private function _inObject($commit, $object)
|
||||
{
|
||||
$object = strtolower($object);
|
||||
if ('branch' === $object) {
|
||||
$objects = $this->getBranches();
|
||||
} else if ('tag' === $object) {
|
||||
$objects = $this->getTags();
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(__('Invalid value for the parameter %1$s: %2$s. Use %3$s.'),
|
||||
'$object',
|
||||
$object,
|
||||
'\'branch\' or \'tag\''));
|
||||
}
|
||||
unset($object);
|
||||
$result = array();
|
||||
if (array_key_exists($commit, $objects)) {
|
||||
$result[] = $commit;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Git "tree" is not the same as the tree we get here.
|
||||
@@ -120,7 +210,9 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
{
|
||||
$folder = ($folder == '/') ? '' : $folder;
|
||||
// now we grab the info about this commit including its tree.
|
||||
$co = $this->getCommit($commit);
|
||||
if (false == ($co = $this->getCommit($commit))) {
|
||||
return false;
|
||||
}
|
||||
if ($folder) {
|
||||
// As we are limiting to a given folder, we need to find
|
||||
// the tree corresponding to this folder.
|
||||
@@ -143,6 +235,7 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
$file->author = 'Unknown';
|
||||
}
|
||||
$file->fullpath = ($folder) ? $folder.'/'.$file->file : $file->file;
|
||||
$file->efullpath = self::smartEncode($file->fullpath);
|
||||
if ($file->type == 'commit') {
|
||||
// We have a submodule
|
||||
$file = $this->getSubmodule($file, $commit);
|
||||
@@ -167,9 +260,14 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
if (!preg_match('/<(.*)>/', $author, $match)) {
|
||||
return null;
|
||||
}
|
||||
$sql = new Pluf_SQL('email=%s', array($match[1]));
|
||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||
return ($users->count() > 0) ? $users[0] : null;
|
||||
foreach (array('email', 'login') as $what) {
|
||||
$sql = new Pluf_SQL($what.'=%s', array($match[1]));
|
||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||
if ($users->count() > 0) {
|
||||
return $users[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getAnonymousAccessUrl($project)
|
||||
@@ -197,14 +295,15 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
|
||||
public function isValidRevision($commit)
|
||||
{
|
||||
return ('commit' == $this->testHash($commit));
|
||||
$type = $this->testHash($commit);
|
||||
return ('commit' == $type || 'tag' == $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a given object hash.
|
||||
*
|
||||
* @param string Object hash.
|
||||
* @return mixed false if not valid or 'blob', 'tree', 'commit'
|
||||
* @return mixed false if not valid or 'blob', 'tree', 'commit', 'tag'
|
||||
*/
|
||||
public function testHash($hash)
|
||||
{
|
||||
@@ -212,26 +311,12 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($hash));
|
||||
$ret = 0; $out = array();
|
||||
exec($cmd, $out, $ret);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Git::testHash', $cmd, $out, $ret);
|
||||
if ($ret != 0) return false;
|
||||
return trim($out[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a commit hash returns an array of files in it.
|
||||
*
|
||||
* A file is a class with the following properties:
|
||||
*
|
||||
* 'perm', 'type', 'size', 'hash', 'file'
|
||||
*
|
||||
* @param string Commit ('HEAD')
|
||||
* @param string Base folder ('')
|
||||
* @return array
|
||||
*/
|
||||
public function filesAtCommit($commit='HEAD', $folder='')
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tree info.
|
||||
*
|
||||
@@ -242,7 +327,7 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
*/
|
||||
public function getTreeInfo($tree, $folder='')
|
||||
{
|
||||
if (!in_array($this->testHash($tree), array('tree', 'commit'))) {
|
||||
if (!in_array($this->testHash($tree), array('tree', 'commit', 'tag'))) {
|
||||
throw new Exception(sprintf(__('Not a valid tree: %s.'), $tree));
|
||||
}
|
||||
$cmd_tmpl = 'GIT_DIR=%s '.Pluf::f('git_path', 'git').' ls-tree -l %s %s';
|
||||
@@ -251,7 +336,7 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
escapeshellarg($tree), escapeshellarg($folder));
|
||||
$out = array();
|
||||
$res = array();
|
||||
exec($cmd, $out);
|
||||
self::exec('IDF_Scm_Git::getTreeInfo', $cmd, $out);
|
||||
foreach ($out as $line) {
|
||||
list($perm, $type, $hash, $size, $file) = preg_split('/ |\t/', $line, 5, PREG_SPLIT_NO_EMPTY);
|
||||
$res[] = (object) array('perm' => $perm, 'type' => $type,
|
||||
@@ -261,7 +346,6 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the file info.
|
||||
*
|
||||
@@ -276,13 +360,16 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($commit));
|
||||
$out = array();
|
||||
exec($cmd, $out);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Git::getPathInfo', $cmd, $out);
|
||||
foreach ($out as $line) {
|
||||
list($perm, $type, $hash, $size, $file) = preg_split('/ |\t/', $line, 5, PREG_SPLIT_NO_EMPTY);
|
||||
if ($totest == $file) {
|
||||
$pathinfo = pathinfo($file);
|
||||
return (object) array('perm' => $perm, 'type' => $type,
|
||||
'size' => $size, 'hash' => $hash,
|
||||
'file' => $file);
|
||||
'fullpath' => $file,
|
||||
'file' => $pathinfo['basename']);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -294,10 +381,10 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
'GIT_DIR=%s '.Pluf::f('git_path', 'git').' cat-file blob %s',
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($def->hash));
|
||||
return ($cmd_only) ? $cmd : shell_exec($cmd);
|
||||
return ($cmd_only)
|
||||
? $cmd : self::shell_exec('IDF_Scm_Git::getFile', $cmd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get commit details.
|
||||
*
|
||||
@@ -319,22 +406,31 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
escapeshellarg($commit));
|
||||
}
|
||||
$out = array();
|
||||
exec($cmd, $out);
|
||||
$log = array();
|
||||
$change = array();
|
||||
$inchange = false;
|
||||
foreach ($out as $line) {
|
||||
if (!$inchange and 0 === strpos($line, 'diff --git a')) {
|
||||
$inchange = true;
|
||||
}
|
||||
if ($inchange) {
|
||||
$change[] = $line;
|
||||
} else {
|
||||
$log[] = $line;
|
||||
}
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Git::getCommit', $cmd, $out, $ret);
|
||||
if ($ret != 0 or count($out) == 0) {
|
||||
return false;
|
||||
}
|
||||
if ($getdiff) {
|
||||
$log = array();
|
||||
$change = array();
|
||||
$inchange = false;
|
||||
foreach ($out as $line) {
|
||||
if (!$inchange and 0 === strpos($line, 'diff --git a')) {
|
||||
$inchange = true;
|
||||
}
|
||||
if ($inchange) {
|
||||
$change[] = $line;
|
||||
} else {
|
||||
$log[] = $line;
|
||||
}
|
||||
}
|
||||
$out = self::parseLog($log);
|
||||
$out[0]->changes = implode("\n", $change);
|
||||
} else {
|
||||
$out = self::parseLog($out);
|
||||
$out[0]->changes = '';
|
||||
}
|
||||
$out = self::parseLog($log, 4);
|
||||
$out[0]->changes = implode("\n", $change);
|
||||
return $out[0];
|
||||
}
|
||||
|
||||
@@ -351,7 +447,8 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
"'commit %H%n'",
|
||||
escapeshellarg($commit));
|
||||
$out = array();
|
||||
exec($cmd, $out);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Git::isCommitLarge', $cmd, $out);
|
||||
$affected = count($out) - 2;
|
||||
$added = 0;
|
||||
$removed = 0;
|
||||
@@ -383,28 +480,29 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
escapeshellarg($this->repo), $n, $this->mediumtree_fmt,
|
||||
escapeshellarg($commit));
|
||||
$out = array();
|
||||
exec($cmd, $out);
|
||||
return self::parseLog($out, 4);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Git::getChangeLog', $cmd, $out);
|
||||
return self::parseLog($out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the log lines of a --pretty=medium log output.
|
||||
*
|
||||
* @param array Lines.
|
||||
* @param int Number of lines in the headers (3)
|
||||
* @return array Change log.
|
||||
*/
|
||||
public static function parseLog($lines, $hdrs=3)
|
||||
public static function parseLog($lines)
|
||||
{
|
||||
$res = array();
|
||||
$c = array();
|
||||
$hdrs += 2;
|
||||
$inheads = true;
|
||||
$next_is_title = false;
|
||||
foreach ($lines as $line) {
|
||||
if (preg_match('/^commit (\w{40})$/', $line)) {
|
||||
if (count($c) > 0) {
|
||||
$c['full_message'] = trim($c['full_message']);
|
||||
$c['full_message'] = IDF_Commit::toUTF8($c['full_message']);
|
||||
$c['title'] = IDF_Commit::toUTF8($c['title']);
|
||||
$res[] = (object) $c;
|
||||
}
|
||||
$c = array();
|
||||
@@ -437,7 +535,9 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$c['full_message'] = trim($c['full_message']);
|
||||
$c['full_message'] = !empty($c['full_message']) ? trim($c['full_message']) : '';
|
||||
$c['full_message'] = IDF_Commit::toUTF8($c['full_message']);
|
||||
$c['title'] = IDF_Commit::toUTF8($c['title']);
|
||||
$res[] = (object) $c;
|
||||
return $res;
|
||||
}
|
||||
@@ -456,7 +556,7 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
* Specific Git Commands
|
||||
* =====================================================
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Get submodule details.
|
||||
*
|
||||
@@ -543,7 +643,8 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
escapeshellarg($this->repo));
|
||||
$skip = 0;
|
||||
$res = array();
|
||||
exec(sprintf($cmd, $skip), $rawlog);
|
||||
self::exec('IDF_Scm_Git::appendBlobInfoCache',
|
||||
sprintf($cmd, $skip), $rawlog);
|
||||
while (count($rawlog) and count($blobs)) {
|
||||
$rawlog = implode("\n", array_reverse($rawlog));
|
||||
foreach ($blobs as $blob => $idx) {
|
||||
@@ -572,7 +673,8 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
}
|
||||
break;
|
||||
}
|
||||
exec(sprintf($cmd, $skip), $rawlog);
|
||||
self::exec('IDF_Scm_Git::appendBlobInfoCache',
|
||||
sprintf($cmd, $skip), $rawlog);
|
||||
}
|
||||
$this->cacheBlobInfo($res);
|
||||
return $res;
|
||||
@@ -590,7 +692,8 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
.sprintf('GIT_DIR=%s '.Pluf::f('git_path', 'git').' log --raw --abbrev=40 --pretty=oneline -500 --skip=%%s',
|
||||
escapeshellarg($this->repo));
|
||||
$skip = 0;
|
||||
exec(sprintf($cmd, $skip), $rawlog);
|
||||
self::exec('IDF_Scm_Git::buildBlobInfoCache',
|
||||
sprintf($cmd, $skip), $rawlog);
|
||||
while (count($rawlog)) {
|
||||
$commit = '';
|
||||
$data = array();
|
||||
@@ -608,7 +711,8 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
$this->cacheBlobInfo($data);
|
||||
$rawlog = array();
|
||||
$skip += 500;
|
||||
exec(sprintf($cmd, $skip), $rawlog);
|
||||
self::exec('IDF_Scm_Git::buildBlobInfoCache',
|
||||
sprintf($cmd, $skip), $rawlog);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -657,10 +761,10 @@ class IDF_Scm_Git extends IDF_Scm
|
||||
if (false === $data) {
|
||||
return $res;
|
||||
}
|
||||
$data = split(chr(30), $data);
|
||||
$data = explode(chr(30), $data);
|
||||
foreach ($data as $rec) {
|
||||
if (isset($hashes[substr($rec, 0, 40)])) {
|
||||
$tmp = split(chr(31), substr($rec, 40), 3);
|
||||
$tmp = explode(chr(31), substr($rec, 40), 3);
|
||||
$res[substr($rec, 0, 40)] =
|
||||
(object) array('hash' => substr($rec, 0, 40),
|
||||
'date' => $tmp[0],
|
||||
|
@@ -25,22 +25,41 @@
|
||||
* Mercurial utils.
|
||||
*
|
||||
*/
|
||||
class IDF_Scm_Mercurial
|
||||
class IDF_Scm_Mercurial extends IDF_Scm
|
||||
{
|
||||
public $repo = '';
|
||||
|
||||
public function __construct($repo)
|
||||
public function __construct($repo, $project=null)
|
||||
{
|
||||
$this->repo = $repo;
|
||||
$this->project = $project;
|
||||
}
|
||||
|
||||
public function getRepositorySize()
|
||||
{
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').'du -sk '
|
||||
.escapeshellarg($this->repo);
|
||||
$out = explode(' ',
|
||||
self::shell_exec('IDF_Scm_Mercurial::getRepositorySize',
|
||||
$cmd),
|
||||
2);
|
||||
return (int) $out[0]*1024;
|
||||
}
|
||||
|
||||
public static function factory($project)
|
||||
{
|
||||
$rep = sprintf(Pluf::f('mercurial_repositories'), $project->shortname);
|
||||
return new IDF_Scm_Mercurial($rep, $project);
|
||||
}
|
||||
|
||||
public function isAvailable()
|
||||
{
|
||||
try {
|
||||
$branches = $this->getBranches();
|
||||
} catch (IDF_Scm_Exception $e) {
|
||||
return false;
|
||||
}
|
||||
return (count($branches) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the string describing the author from the log find the
|
||||
* author in the database.
|
||||
*
|
||||
* @param string Author
|
||||
* @return mixed Pluf_User or null
|
||||
*/
|
||||
public function findAuthor($author)
|
||||
{
|
||||
// We extract the email.
|
||||
@@ -53,27 +72,29 @@ class IDF_Scm_Mercurial
|
||||
return ($users->count() > 0) ? $users[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of the git daemon.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return string URL
|
||||
*/
|
||||
public static function getRemoteAccessUrl($project)
|
||||
public function getMainBranch()
|
||||
{
|
||||
return 'tip';
|
||||
}
|
||||
|
||||
public static function getAnonymousAccessUrl($project)
|
||||
{
|
||||
return sprintf(Pluf::f('mercurial_remote_url'), $project->shortname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this object correctly initialized for the project.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return IDF_Scm_Git
|
||||
*/
|
||||
public static function factory($project)
|
||||
public static function getAuthAccessUrl($project, $user)
|
||||
{
|
||||
$rep = sprintf(Pluf::f('mercurial_repositories'), $project->shortname);
|
||||
return new IDF_Scm_Mercurial($rep);
|
||||
return sprintf(Pluf::f('mercurial_remote_url'), $project->shortname);
|
||||
}
|
||||
|
||||
public function isValidRevision($rev)
|
||||
{
|
||||
$cmd = sprintf(Pluf::f('hg_path', 'hg').' log -R %s -r %s',
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($rev));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Mercurial::isValidRevision', $cmd, $out, $ret);
|
||||
return ($ret == 0) && (count($out) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,24 +111,15 @@ class IDF_Scm_Mercurial
|
||||
escapeshellarg($hash));
|
||||
$ret = 0;
|
||||
$out = array();
|
||||
IDF_Scm::exec($cmd, $out, $ret);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Mercurial::testHash', $cmd, $out, $ret);
|
||||
return ($ret != 0) ? false : 'commit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a commit hash returns an array of files in it.
|
||||
*
|
||||
* A file is a class with the following properties:
|
||||
*
|
||||
* 'perm', 'type', 'size', 'hash', 'file'
|
||||
*
|
||||
* @param string Commit ('HEAD')
|
||||
* @param string Base folder ('')
|
||||
* @return array
|
||||
*/
|
||||
public function filesAtCommit($commit='tip', $folder='')
|
||||
public function getTree($commit, $folder='/', $branch=null)
|
||||
{
|
||||
// now we grab the info about this commit including its tree.
|
||||
$folder = ($folder == '/') ? '' : $folder;
|
||||
$co = $this->getCommit($commit);
|
||||
if ($folder) {
|
||||
// As we are limiting to a given folder, we need to find
|
||||
@@ -143,29 +155,24 @@ class IDF_Scm_Mercurial
|
||||
$cmd = sprintf($cmd_tmpl, escapeshellarg($this->repo), $tree, ($recurse) ? '' : '');
|
||||
$out = array();
|
||||
$res = array();
|
||||
IDF_Scm::exec($cmd, $out);
|
||||
$out_hack = array();
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Mercurial::getTreeInfo', $cmd, $out);
|
||||
$tmp_hack = array();
|
||||
foreach ($out as $line) {
|
||||
while (null !== ($line = array_pop($out))) {
|
||||
list($hash, $perm, $exec, $file) = preg_split('/ |\t/', $line, 4);
|
||||
$file = trim($file);
|
||||
$dir = explode('/', $file, -1);
|
||||
$tmp = '';
|
||||
for ($i=0; $i < count($dir); $i++) {
|
||||
for ($i=0, $n=count($dir); $i<$n; $i++) {
|
||||
if ($i > 0) {
|
||||
$tmp .= '/';
|
||||
}
|
||||
$tmp .= $dir[$i];
|
||||
if (!isset($tmp_hack["empty\t000\t\t$tmp/"])) {
|
||||
$out_hack[] = "empty\t000\t\t$tmp/";
|
||||
$out[] = "empty\t000\t\t$tmp/";
|
||||
$tmp_hack["empty\t000\t\t$tmp/"] = 1;
|
||||
}
|
||||
}
|
||||
$out_hack[] = "$hash\t$perm\t$exec\t$file";
|
||||
}
|
||||
foreach ($out_hack as $line) {
|
||||
list($hash, $perm, $exec, $file) = preg_split('/ |\t/', $line, 4);
|
||||
$file = trim($file);
|
||||
if (preg_match('/^(.*)\/$/', $file, $match)) {
|
||||
$type = 'tree';
|
||||
$file = $match[1];
|
||||
@@ -183,48 +190,47 @@ class IDF_Scm_Mercurial
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$fullpath = ($folder) ? $folder.'/'.$file : $file;
|
||||
$efullpath = self::smartEncode($fullpath);
|
||||
$res[] = (object) array('perm' => $perm, 'type' => $type,
|
||||
'hash' => $hash, 'fullpath' => ($folder) ? $folder.'/'.$file : $file,
|
||||
'file' => $file);
|
||||
'hash' => $hash, 'fullpath' => $fullpath,
|
||||
'efullpath' => $efullpath, 'file' => $file);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file info.
|
||||
*
|
||||
* @param string Commit ('HEAD')
|
||||
* @return false Information
|
||||
*/
|
||||
public function getFileInfo($totest, $commit='tip')
|
||||
public function getPathInfo($totest, $commit='tip')
|
||||
{
|
||||
$cmd_tmpl = Pluf::f('hg_path', 'hg').' manifest -R %s --debug -r %s';
|
||||
$cmd = sprintf($cmd_tmpl, escapeshellarg($this->repo), $commit);
|
||||
$out = array();
|
||||
$res = array();
|
||||
IDF_Scm::exec($cmd, $out);
|
||||
$out_hack = array();
|
||||
$tmp_hack =array();
|
||||
foreach ($out as $line) {
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Mercurial::getPathInfo', $cmd, $out);
|
||||
$tmp_hack = array();
|
||||
while (null !== ($line = array_pop($out))) {
|
||||
list($hash, $perm, $exec, $file) = preg_split('/ |\t/', $line, 4);
|
||||
$file = trim($file);
|
||||
$dir = explode('/', $file, -1);
|
||||
$tmp = '';
|
||||
for ($i=0; $i < count($dir); $i++) {
|
||||
for ($i=0, $n=count($dir); $i<$n; $i++) {
|
||||
if ($i > 0) {
|
||||
$tmp .= '/';
|
||||
}
|
||||
$tmp .= $dir[$i];
|
||||
if ($tmp == $totest) {
|
||||
$pathinfo = pathinfo($totest);
|
||||
return (object) array('perm' => '000', 'type' => 'tree',
|
||||
'hash' => $hash,
|
||||
'fullpath' => $totest,
|
||||
'file' => $pathinfo['basename'],
|
||||
'commit' => $commit
|
||||
);
|
||||
}
|
||||
if (!isset($tmp_hack["empty\t000\t\t$tmp/"])) {
|
||||
$out_hack[] = "empty\t000\t\t$tmp/";
|
||||
$out[] = "empty\t000\t\t$tmp/";
|
||||
$tmp_hack["empty\t000\t\t$tmp/"] = 1;
|
||||
}
|
||||
}
|
||||
$out_hack[] = "$hash\t$perm\t$exec\t$file";
|
||||
}
|
||||
foreach ($out_hack as $line) {
|
||||
list($hash, $perm, $exec, $file) = preg_split('/ |\t/', $line, 4);
|
||||
$file = trim ($file);
|
||||
if (preg_match('/^(.*)\/$/', $file, $match)) {
|
||||
$type = 'tree';
|
||||
$file = $match[1];
|
||||
@@ -232,9 +238,11 @@ class IDF_Scm_Mercurial
|
||||
$type = 'blob';
|
||||
}
|
||||
if ($totest == $file) {
|
||||
$pathinfo = pathinfo($totest);
|
||||
return (object) array('perm' => $perm, 'type' => $type,
|
||||
'hash' => $hash,
|
||||
'file' => $file,
|
||||
'fullpath' => $totest,
|
||||
'file' => $pathinfo['basename'],
|
||||
'commit' => $commit
|
||||
);
|
||||
}
|
||||
@@ -242,19 +250,15 @@ class IDF_Scm_Mercurial
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a blob.
|
||||
*
|
||||
* @param string request_file_info
|
||||
* @param null to be svn client compatible
|
||||
* @return string Raw blob
|
||||
*/
|
||||
public function getBlob($request_file_info, $dummy=null)
|
||||
public function getFile($def, $cmd_only=false)
|
||||
{
|
||||
return IDF_Scm::shell_exec(sprintf(Pluf::f('hg_path', 'hg').' cat -R %s -r %s %s',
|
||||
escapeshellarg($this->repo),
|
||||
$dummy,
|
||||
escapeshellarg($this->repo . '/' . $request_file_info->file)));
|
||||
$cmd = sprintf(Pluf::f('hg_path', 'hg').' cat -R %s -r %s %s',
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($def->commit),
|
||||
escapeshellarg($this->repo.'/'.$def->fullpath));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
return ($cmd_only) ?
|
||||
$cmd : self::shell_exec('IDF_Scm_Mercurial::getFile', $cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,17 +268,59 @@ class IDF_Scm_Mercurial
|
||||
*/
|
||||
public function getBranches()
|
||||
{
|
||||
if (isset($this->cache['branches'])) {
|
||||
return $this->cache['branches'];
|
||||
}
|
||||
$out = array();
|
||||
IDF_Scm::exec(sprintf(Pluf::f('hg_path', 'hg').' branches -R %s',
|
||||
escapeshellarg($this->repo)), $out);
|
||||
$cmd = sprintf(Pluf::f('hg_path', 'hg').' branches -R %s',
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Mercurial::getBranches', $cmd, $out);
|
||||
$res = array();
|
||||
foreach ($out as $b) {
|
||||
preg_match('/(\S+).*\S+:(\S+)/', $b, $match);
|
||||
$res[] = $match[1];
|
||||
$res[$match[1]] = '';
|
||||
}
|
||||
$this->cache['branches'] = $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tags.
|
||||
*
|
||||
* @return array Tags.
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
if (isset($this->cache['tags'])) {
|
||||
return $this->cache['tags'];
|
||||
}
|
||||
$out = array();
|
||||
$cmd = sprintf(Pluf::f('hg_path', 'hg').' tags -R %s',
|
||||
escapeshellarg($this->repo));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Mercurial::getTags', $cmd, $out);
|
||||
$res = array();
|
||||
foreach ($out as $b) {
|
||||
preg_match('/(\S+).*\S+:(\S+)/', $b, $match);
|
||||
$res[$match[1]] = '';
|
||||
}
|
||||
$this->cache['tags'] = $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function inBranches($commit, $path)
|
||||
{
|
||||
return (in_array($commit, array_keys($this->getBranches())))
|
||||
? array($commit) : array();
|
||||
}
|
||||
|
||||
public function inTags($commit, $path)
|
||||
{
|
||||
return (in_array($commit, array_keys($this->getTags())))
|
||||
? array($commit) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get commit details.
|
||||
*
|
||||
@@ -282,14 +328,18 @@ class IDF_Scm_Mercurial
|
||||
* @param bool Get commit diff (false)
|
||||
* @return array Changes
|
||||
*/
|
||||
public function getCommit($commit='tip', $getdiff=false)
|
||||
public function getCommit($commit, $getdiff=false)
|
||||
{
|
||||
if (!$this->isValidRevision($commit)) {
|
||||
return false;
|
||||
}
|
||||
$tmpl = ($getdiff) ?
|
||||
Pluf::f('hg_path', 'hg').' log -p -r %s -R %s' : Pluf::f('hg_path', 'hg').' log -r %s -R %s';
|
||||
$cmd = sprintf($tmpl,
|
||||
escapeshellarg($commit), escapeshellarg($this->repo));
|
||||
$out = array();
|
||||
IDF_Scm::exec($cmd, $out);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Mercurial::getCommit', $cmd, $out);
|
||||
$log = array();
|
||||
$change = array();
|
||||
$inchange = false;
|
||||
@@ -330,7 +380,8 @@ class IDF_Scm_Mercurial
|
||||
{
|
||||
$cmd = sprintf(Pluf::f('hg_path', 'hg').' log -R %s -l%s ', escapeshellarg($this->repo), $n, $commit);
|
||||
$out = array();
|
||||
IDF_Scm::exec($cmd, $out);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Mercurial::getChangeLog', $cmd, $out);
|
||||
return self::parseLog($out, 6);
|
||||
}
|
||||
|
||||
@@ -386,8 +437,8 @@ class IDF_Scm_Mercurial
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$c['tree'] = $c['commit'];
|
||||
$c['full_message'] = trim($c['full_message']);
|
||||
$c['tree'] = !empty($c['commit']) ? trim($c['commit']) : '';
|
||||
$c['full_message'] = !empty($c['full_message']) ? trim($c['full_message']) : '';
|
||||
$res[] = (object) $c;
|
||||
return $res;
|
||||
}
|
||||
|
@@ -22,24 +22,28 @@
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* SVN utils.
|
||||
*
|
||||
* Subversion backend.
|
||||
* When a branch is not a branch.
|
||||
*
|
||||
* Contrary to most other SCMs, Subversion is using folders to manage
|
||||
* the branches and so what is either the commit or the branch in
|
||||
* other SCMs is the revision number with Subversion. So, do not be
|
||||
* surprised if you have the feeling that the methods are not really
|
||||
* returning what could be expected from their names.
|
||||
*/
|
||||
class IDF_Scm_Svn extends IDF_Scm
|
||||
{
|
||||
public $repo = '';
|
||||
|
||||
public $username = '';
|
||||
public $password = '';
|
||||
private $assoc = array('dir' => 'tree',
|
||||
'file' => 'blob');
|
||||
|
||||
private $commit=array();
|
||||
|
||||
public function __construct($repo, $username='', $password='')
|
||||
public function __construct($repo, $project=null)
|
||||
{
|
||||
$this->repo = $repo;
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
$this->project = $project;
|
||||
$this->cache['commitmess'] = array();
|
||||
}
|
||||
|
||||
public function isAvailable()
|
||||
@@ -47,6 +51,17 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getRepositorySize()
|
||||
{
|
||||
if (strpos($this->repo, 'file://') !== 0) {
|
||||
return -1;
|
||||
}
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').'du -sk '
|
||||
.escapeshellarg(substr($this->repo, 7));
|
||||
$out = explode(' ', self::shell_exec('IDF_Scm_Svn::getRepositorySize', $cmd), 2);
|
||||
return (int) $out[0]*1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the string describing the author from the log find the
|
||||
* author in the database.
|
||||
@@ -78,6 +93,23 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
return sprintf(Pluf::f('svn_remote_url'), $project->shortname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of the subversion repository.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return string URL
|
||||
*/
|
||||
public static function getAuthAccessUrl($project, $user)
|
||||
{
|
||||
$conf = $project->getConf();
|
||||
if (false !== ($url=$conf->getVal('svn_remote_url', false))
|
||||
&& !empty($url)) {
|
||||
// Remote repository
|
||||
return $url;
|
||||
}
|
||||
return sprintf(Pluf::f('svn_remote_url'), $project->shortname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this object correctly initialized for the project.
|
||||
*
|
||||
@@ -91,12 +123,13 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
if (false !== ($rep=$conf->getVal('svn_remote_url', false))
|
||||
&& !empty($rep)) {
|
||||
// Remote repository
|
||||
return new IDF_Scm_Svn($rep,
|
||||
$conf->getVal('svn_username'),
|
||||
$conf->getVal('svn_password'));
|
||||
$scm = new IDF_Scm_Svn($rep, $project);
|
||||
$scm->username = $conf->getVal('svn_username');
|
||||
$scm->password = $conf->getVal('svn_password');
|
||||
return $scm;
|
||||
} else {
|
||||
$rep = sprintf(Pluf::f('svn_repositories'), $project->shortname);
|
||||
return new IDF_Scm_Svn($rep);
|
||||
return new IDF_Scm_Svn($rep, $project);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +146,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($rev));
|
||||
exec($cmd, $out, $ret);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Svn::isValidRevision', $cmd, $out, $ret);
|
||||
return (0 == $ret);
|
||||
}
|
||||
|
||||
@@ -135,9 +169,10 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --xml --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$path),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($path)),
|
||||
escapeshellarg($rev));
|
||||
$xmlInfo = shell_exec($cmd);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$xmlInfo = self::shell_exec('IDF_Scm_Svn::testHash', $cmd);
|
||||
|
||||
// If exception is thrown, return false
|
||||
try {
|
||||
@@ -156,29 +191,27 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
return 'commit';
|
||||
}
|
||||
|
||||
public function getTree($rev='HEAD', $folder='')
|
||||
public function getTree($commit, $folder='/', $branch=null)
|
||||
{
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' ls --xml --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$folder),
|
||||
escapeshellarg($rev));
|
||||
$xmlLs = shell_exec($cmd);
|
||||
$xml = simplexml_load_string($xmlLs);
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($folder)),
|
||||
escapeshellarg($commit));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getTree', $cmd));
|
||||
$res = array();
|
||||
$folder = (strlen($folder)) ? $folder.'/' : '';
|
||||
$folder = (strlen($folder) and ($folder != '/')) ? $folder.'/' : '';
|
||||
foreach ($xml->list->entry as $entry) {
|
||||
$file = array();
|
||||
$file['type'] = $this->assoc[(string) $entry['kind']];
|
||||
$file['file'] = (string) $entry->name;
|
||||
$file['fullpath'] = $folder.((string) $entry->name);
|
||||
$file['efullpath'] = self::smartEncode($file['fullpath']);
|
||||
$file['date'] = gmdate('Y-m-d H:i:s',
|
||||
strtotime((string) $entry->commit->date));
|
||||
$file['rev'] = (string) $entry->commit['revision'];
|
||||
// Get commit message
|
||||
$currentReposFile = $this->repo.'/'.$folder.$file['file'];
|
||||
$file['log'] = $this->getCommitMessage($currentReposFile, $rev);
|
||||
|
||||
$file['log'] = $this->getCommitMessage($file['rev']);
|
||||
// Get the size if the type is blob
|
||||
if ($file['type'] == 'blob') {
|
||||
$file['size'] = (string) $entry->size;
|
||||
@@ -192,66 +225,71 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
|
||||
|
||||
/**
|
||||
* Get a commit message for given file and revision.
|
||||
* Get the commit message of a revision revision.
|
||||
*
|
||||
* @param string File
|
||||
* @param string Commit ('HEAD')
|
||||
*
|
||||
* @return String commit message
|
||||
*/
|
||||
private function getCommitMessage($file, $rev='HEAD')
|
||||
private function getCommitMessage($rev='HEAD')
|
||||
{
|
||||
if (isset($commit[$rev])) return $commit[$rev];
|
||||
if (isset($this->cache['commitmess'][$rev])) {
|
||||
return $this->cache['commitmess'][$rev];
|
||||
}
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --xml --limit 1 --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($file),
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($rev));
|
||||
$xmlLog = shell_exec($cmd);
|
||||
$xml = simplexml_load_string($xmlLog);
|
||||
$commit[$rev]=(string) $xml->logentry->msg;
|
||||
return (string) $xml->logentry->msg;
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getCommitMessage', $cmd));
|
||||
$this->cache['commitmess'][$rev] = (string) $xml->logentry->msg;
|
||||
return $this->cache['commitmess'][$rev];
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME: Need to check the case of an inexisting file.
|
||||
*/
|
||||
public function getPathInfo($totest, $rev='HEAD')
|
||||
public function getPathInfo($filename, $rev=null)
|
||||
{
|
||||
if ($rev == null) {
|
||||
$rev = 'HEAD';
|
||||
}
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' info --xml --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$totest),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($filename)),
|
||||
escapeshellarg($rev));
|
||||
$xmlInfo = shell_exec($cmd);
|
||||
$xml = simplexml_load_string($xmlInfo);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getPathInfo', $cmd));
|
||||
if (!isset($xml->entry)) {
|
||||
return false;
|
||||
}
|
||||
$entry = $xml->entry;
|
||||
$file = array();
|
||||
$file['fullpath'] = $totest;
|
||||
$file['fullpath'] = $filename;
|
||||
$file['hash'] = (string) $entry->repository->uuid;
|
||||
$file['type'] = $this->assoc[(string) $entry['kind']];
|
||||
$file['file'] = $totest;
|
||||
$file['rev'] = (string) $entry->commit['revision'];
|
||||
$pathinfo = pathinfo($filename);
|
||||
$file['file'] = $pathinfo['basename'];
|
||||
$file['rev'] = $rev;
|
||||
$file['author'] = (string) $entry->author;
|
||||
$file['date'] = gmdate('Y-m-d H:i:s', strtotime((string) $entry->commit->date));
|
||||
$file['size'] = (string) $entry->size;
|
||||
$file['log'] = '';
|
||||
|
||||
return (object) $file;
|
||||
}
|
||||
|
||||
public function getFile($def)
|
||||
public function getFile($def, $cmd_only=false)
|
||||
{
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' cat --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$def->fullpath),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($def->fullpath)),
|
||||
escapeshellarg($def->rev));
|
||||
return shell_exec($cmd);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
return ($cmd_only) ?
|
||||
$cmd : self::shell_exec('IDF_Scm_Svn::getFile', $cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subversion branches are repository based.
|
||||
* Subversion branches are folder based.
|
||||
*
|
||||
* One need to list the folder to know them.
|
||||
*/
|
||||
@@ -260,11 +298,13 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
if (isset($this->cache['branches'])) {
|
||||
return $this->cache['branches'];
|
||||
}
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' ls --username=%s --password=%s %s@HEAD',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/branches'));
|
||||
exec($cmd, $out, $ret);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Svn::getBranches', $cmd, $out, $ret);
|
||||
if ($ret == 0) {
|
||||
foreach ($out as $entry) {
|
||||
if (substr(trim($entry), -1) == '/') {
|
||||
@@ -278,14 +318,45 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/trunk'));
|
||||
exec($cmd, $out, $ret);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Svn::getBranches', $cmd, $out, $ret);
|
||||
if ($ret == 0) {
|
||||
$res = array_merge(array('trunk' => 'trunk'), $res);
|
||||
$res = array('trunk' => 'trunk') + $res;
|
||||
}
|
||||
$this->cache['branches'] = $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subversion tags are folder based.
|
||||
*
|
||||
* One need to list the folder to know them.
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
if (isset($this->cache['tags'])) {
|
||||
return $this->cache['tags'];
|
||||
}
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' ls --username=%s --password=%s %s@HEAD',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/tags'));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
self::exec('IDF_Scm_Svn::getTags', $cmd, $out, $ret);
|
||||
if ($ret == 0) {
|
||||
foreach ($out as $entry) {
|
||||
if (substr(trim($entry), -1) == '/') {
|
||||
$tag = substr(trim($entry), 0, -1);
|
||||
$res[$tag] = 'tags/'.$tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
ksort($res);
|
||||
$this->cache['tags'] = $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function getMainBranch()
|
||||
{
|
||||
return 'HEAD';
|
||||
@@ -301,29 +372,43 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
return array();
|
||||
}
|
||||
|
||||
public function inTags($commit, $path)
|
||||
{
|
||||
foreach ($this->getTags() as $tag => $tpath) {
|
||||
if ($tpath and 0 === strpos($path, $tpath)) {
|
||||
return array($tag);
|
||||
}
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get commit details.
|
||||
*
|
||||
* @param string Commit ('HEAD')
|
||||
* @param string Commit
|
||||
* @param bool Get commit diff (false)
|
||||
* @return array Changes
|
||||
*/
|
||||
public function getCommit($rev='HEAD', $getdiff=false)
|
||||
public function getCommit($commit, $getdiff=false)
|
||||
{
|
||||
if (!$this->isValidRevision($commit)) {
|
||||
return false;
|
||||
}
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --xml --limit 1 -v --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($rev));
|
||||
$xmlRes = shell_exec($cmd);
|
||||
escapeshellarg($commit));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$xmlRes = self::shell_exec('IDF_Scm_Svn::getCommit', $cmd);
|
||||
$xml = simplexml_load_string($xmlRes);
|
||||
$res['author'] = (string) $xml->logentry->author;
|
||||
$res['date'] = gmdate('Y-m-d H:i:s', strtotime((string) $xml->logentry->date));
|
||||
$res['title'] = (string) $xml->logentry->msg;
|
||||
$res['commit'] = (string) $xml->logentry['revision'];
|
||||
$res['changes'] = ($getdiff) ? $this->getDiff($rev) : '';
|
||||
$res['changes'] = ($getdiff) ? $this->getDiff($commit) : '';
|
||||
$res['tree'] = '';
|
||||
return (object) $res;
|
||||
}
|
||||
@@ -345,7 +430,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
$cmd = sprintf(Pluf::f('svnlook_path', 'svnlook').' changed -r %s %s',
|
||||
escapeshellarg($commit),
|
||||
escapeshellarg($repo));
|
||||
$out = shell_exec($cmd);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$out = self::shell_exec('IDF_Scm_Svn::isCommitLarge', $cmd);
|
||||
$lines = preg_split("/\015\012|\015|\012/", $out);
|
||||
return (count($lines) > 100);
|
||||
}
|
||||
@@ -358,42 +444,45 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo));
|
||||
return shell_exec($cmd);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
return self::shell_exec('IDF_Scm_Svn::getDiff', $cmd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get latest changes.
|
||||
*
|
||||
* @param string Commit ('HEAD').
|
||||
* @param string Revision or ('HEAD').
|
||||
* @param int Number of changes (10).
|
||||
*
|
||||
* @return array Changes.
|
||||
*/
|
||||
public function getChangeLog($rev='HEAD', $n=10)
|
||||
public function getChangeLog($branch=null, $n=10)
|
||||
{
|
||||
if ($branch != 'HEAD' and !preg_match('/^\d+$/', $branch)) {
|
||||
// we accept only revisions or HEAD
|
||||
$branch = 'HEAD';
|
||||
}
|
||||
$res = array();
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' log --xml -v --limit %s --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($n),
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($rev));
|
||||
$xmlRes = shell_exec($cmd);
|
||||
escapeshellarg($branch));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$xmlRes = self::shell_exec('IDF_Scm_Svn::getChangeLog', $cmd);
|
||||
$xml = simplexml_load_string($xmlRes);
|
||||
|
||||
$res = array();
|
||||
foreach ($xml->logentry as $entry) {
|
||||
$log = array();
|
||||
$log['author'] = (string) $entry->author;
|
||||
$log['date'] = gmdate('Y-m-d H:i:s', strtotime((string) $entry->date));
|
||||
$log['title'] = (string) $entry->msg;
|
||||
$split = preg_split("[\n\r]", (string) $entry->msg, 2);
|
||||
$log['title'] = $split[0];
|
||||
$log['commit'] = (string) $entry['revision'];
|
||||
$log['full_message'] = '';
|
||||
|
||||
$log['full_message'] = (isset($split[1])) ? trim($split[1]) : '';
|
||||
$res[] = (object) $log;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
@@ -411,9 +500,10 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
$cmd = sprintf(Pluf::f('svn_path', 'svn').' proplist --xml --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$path),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($path)),
|
||||
escapeshellarg($rev));
|
||||
$xmlProps = shell_exec($cmd);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$xmlProps = self::shell_exec('IDF_Scm_Svn::getProperties', $cmd);
|
||||
$props = simplexml_load_string($xmlProps);
|
||||
|
||||
// No properties, returns an empty array
|
||||
@@ -446,9 +536,10 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
escapeshellarg($property),
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$path),
|
||||
escapeshellarg($this->repo.'/'.self::smartEncode($path)),
|
||||
escapeshellarg($rev));
|
||||
$xmlProp = shell_exec($cmd);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$xmlProp = self::shell_exec('IDF_Scm_Svn::getProperty', $cmd);
|
||||
$prop = simplexml_load_string($xmlProp);
|
||||
|
||||
return (string) $prop->target->property;
|
||||
@@ -470,7 +561,8 @@ class IDF_Scm_Svn extends IDF_Scm
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($rev));
|
||||
$xmlInfo = shell_exec($cmd);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||
$xmlInfo = self::shell_exec('IDF_Scm_Svn::getLastCommit', $cmd);
|
||||
|
||||
$xml = simplexml_load_string($xmlInfo);
|
||||
return (string) $xml->entry->commit['revision'];
|
||||
|
@@ -59,7 +59,7 @@ class IDF_Search extends Pluf_Search
|
||||
$words_flat[] = $word;
|
||||
}
|
||||
$word_ids = self::getWordIds($words_flat);
|
||||
if (in_array(null, $word_ids)) {
|
||||
if (in_array(null, $word_ids) or count($word_ids) == 0) {
|
||||
return array();
|
||||
}
|
||||
return self::mySearchDocuments($word_ids, $project, $model);
|
||||
@@ -127,9 +127,21 @@ class IDF_Search extends Pluf_Search
|
||||
if ($ids[$i] === null) {
|
||||
$word = new Pluf_Search_Word();
|
||||
$word->word = $words_flat[$i];
|
||||
$word->create();
|
||||
$ids[$i] = $word->id;
|
||||
$new_words++;
|
||||
try {
|
||||
$word->create();
|
||||
$new_words++;
|
||||
$ids[$i] = $word->id;
|
||||
} catch (Exception $e) {
|
||||
// 100% of the time, the word has been created
|
||||
// by another process in the background.
|
||||
$r_ids = self::getWordIds(array($word->word));
|
||||
if ($r_ids[0]) {
|
||||
$ids[$i] = $r_ids[0];
|
||||
} else {
|
||||
// give up for this word
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($done[$ids[$i]])) {
|
||||
continue;
|
||||
|
@@ -37,22 +37,26 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
||||
$this->project = $request->project;
|
||||
$this->request = $request;
|
||||
$this->scm = IDF_Scm::get($request->project);
|
||||
if ($wordwrap) $text = wordwrap($text, 69, "\n", true);
|
||||
if ($esc) $text = Pluf_esc($text);
|
||||
if ($autolink) {
|
||||
$text = preg_replace('#([a-z]+://[^\s\(\)]+)#i',
|
||||
'<a href="\1">\1</a>', $text);
|
||||
}
|
||||
if ($request->rights['hasIssuesAccess']) {
|
||||
$text = preg_replace_callback('#(issues?|bugs?|tickets?)\s+(\d+)((\s+and|\s+or|,)\s+(\d+)){0,}#im',
|
||||
$text = preg_replace_callback('#((?:issue|bug|ticket)(s)?\s+|\s+\#)(\d+)(\#ic\d+)?(?(2)((?:[, \w]+(?:\s+\#)?)?\d+(?:\#ic\d+)?){0,})#im',
|
||||
array($this, 'callbackIssues'), $text);
|
||||
}
|
||||
if ($request->rights['hasReviewAccess']) {
|
||||
$text = preg_replace_callback('#(reviews?\s+)(\d+(?:(?:\s+and|\s+or|,)\s+\d+)*)\b#i',
|
||||
array($this, 'callbackReviews'), $text);
|
||||
}
|
||||
if ($request->rights['hasSourceAccess']) {
|
||||
$text = preg_replace_callback('#(commits?\s+)([0-9a-f]{1,40}(?:(?:\s+and|\s+or|,)\s+[0-9a-f]{1,40})*)\b#i',
|
||||
array($this, 'callbackCommits'), $text);
|
||||
$text = preg_replace_callback('#(src:)([^\s\(\)]+)#im',
|
||||
$text = preg_replace_callback('#(src:)([^\s\(\)\\\\]+(?:(\\\\)\s+[^\s\(\)\\\\]+){0,})+#im',
|
||||
array($this, 'callbackSource'), $text);
|
||||
}
|
||||
if ($wordwrap) $text = Pluf_Text::wrapHtml($text, 69, "\n");
|
||||
if ($nl2br) $text = nl2br($text);
|
||||
if ($echo) {
|
||||
echo $text;
|
||||
@@ -66,18 +70,29 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
||||
*/
|
||||
function callbackIssues($m)
|
||||
{
|
||||
if (count($m) == 3) {
|
||||
$issue = new IDF_Issue($m[2]);
|
||||
if ($issue->id > 0 and $issue->project == $this->project->id) {
|
||||
return $this->linkIssue($issue, $m[1].' '.$m[2]);
|
||||
} else {
|
||||
return $m[0]; // not existing issue.
|
||||
$c = count($m);
|
||||
if (4 === $c || 5 === $c) {
|
||||
$issue = new IDF_Issue($m[3]);
|
||||
if (0 < $issue->id and $issue->project == $this->project->id) {
|
||||
$m[1] = trim($m[1]);
|
||||
$prefix = '';
|
||||
if ('#' === $m[1]) {
|
||||
$title = $m[1].$m[3];
|
||||
$prefix = mb_substr($m[0], 0, strpos($m[0], $m[1])); // fixes \n matches
|
||||
} else {
|
||||
$title = $m[1].' '.$m[3];
|
||||
}
|
||||
if (4 === $c) {
|
||||
return $prefix.$this->linkIssue($issue, $title);
|
||||
} else {
|
||||
return $prefix.$this->linkIssue($issue, $title, $m[4]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return preg_replace_callback('/(\d+)/',
|
||||
array($this, 'callbackIssue'),
|
||||
$m[0]);
|
||||
return $m[0]; // not existing issue.
|
||||
}
|
||||
return preg_replace_callback('#(\#)?(\d+)(\#ic\d+)?#',
|
||||
array($this, 'callbackIssue'),
|
||||
$m[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,12 +103,14 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
||||
*/
|
||||
function callbackIssue($m)
|
||||
{
|
||||
$issue = new IDF_Issue($m[1]);
|
||||
if ($issue->id > 0 and $issue->project == $this->project->id) {
|
||||
return $this->linkIssue($issue, $m[1]);
|
||||
} else {
|
||||
return $m[0]; // not existing issue.
|
||||
$issue = new IDF_Issue($m[2]);
|
||||
if (0 < $issue->id and $issue->project == $this->project->id) {
|
||||
if (4 === count($m)) {
|
||||
return $this->linkIssue($issue, $m[1].$m[2], $m[3]);
|
||||
}
|
||||
return $this->linkIssue($issue, $m[1].$m[2]);
|
||||
}
|
||||
return $m[0]; // not existing issue.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,33 +143,61 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
||||
*/
|
||||
function callbackCommit($m)
|
||||
{
|
||||
try {
|
||||
if ('commit' != $this->scm->testHash($m[0])) {
|
||||
return $m[0]; // not a commit.
|
||||
}
|
||||
} catch (IDF_Scm_Exception $e) {
|
||||
return $m[0]; // commit not found.
|
||||
}
|
||||
$co = $this->scm->getCommit($m[0]);
|
||||
if (!$co) {
|
||||
return $m[0]; // not a commit.
|
||||
}
|
||||
return '<a href="'
|
||||
.Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit', array($this->project->shortname, $co->commit))
|
||||
.'">'.$m[0].'</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* General call back to convert reviews to HTML links.
|
||||
*
|
||||
* @param array $m Single regex match.
|
||||
* @return string Content with converted reviews.
|
||||
*/
|
||||
function callbackReviews($m)
|
||||
{
|
||||
$keyword = rtrim($m[1]);
|
||||
if ('reviews' === $keyword) {
|
||||
return $m[1].preg_replace_callback('#\b(\d+)\b#i', array($this, 'callbackReview'), $m[2]);
|
||||
} else if ('review' === $keyword) {
|
||||
return $m[1].call_user_func(array($this, 'callbackReview'), array('', $m[2]));
|
||||
}
|
||||
return $m[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert plaintext commit to HTML link. Called from callbackReviews.
|
||||
*
|
||||
* Regex callback for {@link IDF_Template_IssueComment::callbackReviews()}.
|
||||
*
|
||||
* @param array Single regex match.
|
||||
* @return string HTML A element with review.
|
||||
*/
|
||||
function callbackReview($m)
|
||||
{
|
||||
$review = new IDF_Review($m[1]);
|
||||
if ($review->id > 0 and $review->project == $this->project->id) {
|
||||
return $this->linkReview($review, $m[1]);
|
||||
} else {
|
||||
return $m[0]; // not existing issue.
|
||||
}
|
||||
}
|
||||
|
||||
function callbackSource($m)
|
||||
{
|
||||
$branches = $this->scm->getBranches();
|
||||
if (count($branches) == 0) return $m[0];
|
||||
if (!$this->scm->isAvailable()) return $m[0];
|
||||
$file = $m[2];
|
||||
if ('commit' != $this->scm->testHash($branches[0], $file)) {
|
||||
return $m[0];
|
||||
}
|
||||
$request_file_info = $this->scm->getFileInfo($file, $branches[0]);
|
||||
if (!empty($m[3])) $file = str_replace($m[3], '', $file);
|
||||
$request_file_info = $this->scm->getPathInfo($file);
|
||||
if (!$request_file_info) {
|
||||
return $m[0];
|
||||
}
|
||||
if ($request_file_info->type != 'tree') {
|
||||
return $m[1].'<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Source::tree', array($this->project->shortname, $branches[0], $file)).'">'.$m[2].'</a>';
|
||||
return $m[1].'<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Source::tree', array($this->project->shortname, $this->scm->getMainBranch(), $file)).'">'.$file.'</a>';
|
||||
}
|
||||
return $m[0];
|
||||
}
|
||||
@@ -164,10 +209,24 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
||||
* @param string Name of the link.
|
||||
* @return string Linked issue.
|
||||
*/
|
||||
public function linkIssue($issue, $title)
|
||||
public function linkIssue($issue, $title, $anchor='')
|
||||
{
|
||||
$ic = (in_array($issue->status, $this->project->getTagIdsByStatus('closed'))) ? 'issue-c' : 'issue-o';
|
||||
return '<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||
array($this->project->shortname, $issue->id)).'" class="'.$ic.'" title="'.Pluf_esc($issue->summary).'">'.Pluf_esc($title).'</a>';
|
||||
array($this->project->shortname, $issue->id)).$anchor.'" class="'.$ic.'" title="'.Pluf_esc($issue->summary).'">'.Pluf_esc($title).'</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the link to a review.
|
||||
*
|
||||
* @param IDF_Review Review.
|
||||
* @param string Name of the link.
|
||||
* @return string Linked review.
|
||||
*/
|
||||
public function linkReview($review, $title, $anchor='')
|
||||
{
|
||||
$ic = (in_array($review->status, $this->project->getTagIdsByStatus('closed'))) ? 'issue-c' : 'issue-o';
|
||||
return '<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
|
||||
array($this->project->shortname, $review->id)).$anchor.'" class="'.$ic.'" title="'.Pluf_esc($review->summary).'">'.Pluf_esc($title).'</a>';
|
||||
}
|
||||
}
|
||||
|
@@ -39,8 +39,14 @@ class IDF_Template_Markdown extends Pluf_Template_Tag
|
||||
// Replace like in the issue text
|
||||
$tag = new IDF_Template_IssueComment();
|
||||
$text = $tag->start($text, $request, false, false, false, false);
|
||||
// Replace [[[path/to/file.mdtext, commit]]] with embedding
|
||||
// the content of the file into the wki page
|
||||
if ($this->request->rights['hasSourceAccess']) {
|
||||
$text = preg_replace_callback('#\[\[\[([^\,]+)(?:, ([^/]+))?\]\]\]#im',
|
||||
array($this, 'callbackEmbeddedDoc'),
|
||||
$text);
|
||||
}
|
||||
// Replace [[PageName]] with corresponding link to the page.
|
||||
// if not the right to see the
|
||||
$text = preg_replace_callback('#\[\[([A-Za-z0-9\-]+)\]\]#im',
|
||||
array($this, 'callbackWikiPage'),
|
||||
$text);
|
||||
@@ -65,5 +71,25 @@ class IDF_Template_Markdown extends Pluf_Template_Tag
|
||||
}
|
||||
return '<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view', array($this->project->shortname, $pages[0]->title)).'" title="'.Pluf_esc($pages[0]->summary).'">'.$m[1].'</a>';
|
||||
}
|
||||
|
||||
function callbackEmbeddedDoc($m)
|
||||
{
|
||||
$scm = IDF_Scm::get($this->request->project);
|
||||
$view_source = new IDF_Views_Source();
|
||||
$match = array('dummy', $this->request->project->shortname);
|
||||
$match[] = (isset($m[2])) ? $m[2] : $scm->getMainBranch();
|
||||
$match[] = $m[1];
|
||||
$res = $view_source->getFile($this->request, $match);
|
||||
if ($res->status_code != 200) {
|
||||
return $m[0];
|
||||
}
|
||||
$info = pathinfo($m[1]);
|
||||
$fileinfo = array($res->headers['Content-Type'], $m[1],
|
||||
isset($info['extension']) ? $info['extension'] : 'bin');
|
||||
if (!IDF_Views_Source::isText($fileinfo)) {
|
||||
return $m[0];
|
||||
}
|
||||
return $res->content;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -119,6 +119,7 @@ class IDF_Template_MarkdownPrefilter extends Pluf_Text_HTML_Filter
|
||||
'strong' => array(),
|
||||
'table' => array('summary'),
|
||||
'td' => array('style'),
|
||||
'th' => array(),
|
||||
'tr' => array(),
|
||||
'ul' => array(),
|
||||
);
|
||||
|
@@ -40,12 +40,48 @@ class IDF_Tests_TestGit extends UnitTestCase
|
||||
|
||||
}
|
||||
|
||||
public function testGitCache()
|
||||
/**
|
||||
* parse a log encoded in iso 8859-1
|
||||
*/
|
||||
public function testParseIsoLog()
|
||||
{
|
||||
$repo = substr(dirname(__FILE__), 0, -strlen('src/IDF/Tests')).'/.git';
|
||||
$repo = '/home/loa/Vendors/linux-git/.git';
|
||||
$git = new IDF_Scm_Git($repo);
|
||||
$git->buildBlobInfoCache();
|
||||
//$git->getCachedBlobInfo(array());
|
||||
$log_lines = preg_split("/\015\012|\015|\012/", file_get_contents(dirname(__FILE__).'/data/git-log-iso-8859-1.txt'));
|
||||
$log = IDF_Scm_Git::parseLog($log_lines);
|
||||
$titles = array(
|
||||
array('Quick Profiler entfernt', 'UTF-8'),
|
||||
array('Anwendungsmenu Divider eingefügt', 'ISO-8859-1'),
|
||||
array('Anwendungen aufäumen', 'ISO-8859-1'),
|
||||
);
|
||||
foreach ($log as $change) {
|
||||
list($title, $senc) = array_shift($titles);
|
||||
list($conv, $encoding) = IDF_Commit::toUTF8($change->title, true);
|
||||
$this->assertEqual($title, $conv);
|
||||
$this->assertEqual($senc, $encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a log encoded in iso 8859-2
|
||||
*/
|
||||
public function testParseIsoLog2()
|
||||
{
|
||||
$log_lines = preg_split("/\015\012|\015|\012/", file_get_contents(dirname(__FILE__).'/data/git-log-iso-8859-2.txt'));
|
||||
$log = IDF_Scm_Git::parseLog($log_lines);
|
||||
$titles = array(
|
||||
array('Doda³em model','ISO-8859-1'),
|
||||
array('Doda³em model','ISO-8859-1'),
|
||||
// The Good result is 'Dodałem model', the
|
||||
// problem is that in that case, one cannot
|
||||
// distinguish between latin1 and latin2. We
|
||||
// will need to add a way for the project
|
||||
// admin to set the priority between the
|
||||
// encodings.
|
||||
);
|
||||
foreach ($log as $change) {
|
||||
list($title, $senc) = array_shift($titles);
|
||||
list($conv, $encoding) = IDF_Commit::toUTF8($change->title, true);
|
||||
$this->assertEqual($title, $conv);
|
||||
$this->assertEqual($senc, $encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
src/IDF/Tests/data/git-log-iso-8859-1.txt
Normal file
19
src/IDF/Tests/data/git-log-iso-8859-1.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
commit 11531a9dbc64a65150f2f38fbea7cef9d478a123
|
||||
Author: unknown <a@(none)>
|
||||
Date: Fri Jul 3 01:44:11 2009 +0200
|
||||
|
||||
Quick Profiler entfernt
|
||||
|
||||
commit 11531a9dbc64a65150f2f38fbea7cef9d478a123
|
||||
Author: unknown <a@(none)>
|
||||
Date: Wed Jul 1 15:51:22 2009 +0200
|
||||
|
||||
Anwendungsmenu Divider eingef<65>gt
|
||||
|
||||
commit 11531a9dbc64a65150f2f38fbea7cef9d478a123
|
||||
Author: unknown <a@(none)>
|
||||
Date: Wed Jul 1 15:05:41 2009 +0200
|
||||
|
||||
Anwendungen auf<75>umen
|
||||
|
||||
|
12
src/IDF/Tests/data/git-log-iso-8859-2.txt
Normal file
12
src/IDF/Tests/data/git-log-iso-8859-2.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
commit 11531a9dbc64a65150f2f38fbea7cef9d478a123
|
||||
Author: unknown <a@(none)>
|
||||
Date: Fri Jul 3 01:44:11 2009 +0200
|
||||
|
||||
Doda<64>em model
|
||||
|
||||
commit 11531a9dbc64a65150f2f38fbea7cef9d478a123
|
||||
Author: unknown <a@(none)>
|
||||
Date: Fri Jul 3 01:44:11 2009 +0200
|
||||
|
||||
Doda<64>em model
|
||||
|
@@ -128,7 +128,7 @@ class IDF_Timeline extends Pluf_Model
|
||||
$t->model_id = $item->id;
|
||||
$t->model_class = $item->_model;
|
||||
$t->create();
|
||||
return true;
|
||||
return $t;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -56,6 +56,12 @@ class IDF_Upload extends Pluf_Model
|
||||
'size' => 250,
|
||||
'verbose' => __('summary'),
|
||||
),
|
||||
'changelog' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Text',
|
||||
'blank' => true,
|
||||
'verbose' => __('changes'),
|
||||
),
|
||||
'file' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_File',
|
||||
@@ -183,33 +189,62 @@ class IDF_Upload extends Pluf_Model
|
||||
$out .= sprintf(__('<a href="%1$s" title="View download">Download %2$d</a>, %3$s'), $url, $this->id, Pluf_esc($this->summary)).'</td>';
|
||||
$out .= '</tr>';
|
||||
$out .= "\n".'<tr class="extra"><td colspan="2">
|
||||
<div class="helptext right">'.sprintf(__('Addition of <a href="%s">download %d</a>'), $url, $this->id).', '.__('by').' '.$user.'</div></td></tr>';
|
||||
<div class="helptext right">'.sprintf(__('Addition of <a href="%s">download %d</a>, by %s'), $url, $this->id, $user).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
|
||||
public function feedFragment($request)
|
||||
{
|
||||
$base = '<entry>
|
||||
<title>%%title%%</title>
|
||||
<link href="%%url%%"/>
|
||||
<id>%%url%%</id>
|
||||
<updated>%%date%%</updated>
|
||||
<content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
|
||||
%%content%%
|
||||
</div></content>
|
||||
</entry>';
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
|
||||
array($request->project->shortname,
|
||||
$this->id));
|
||||
$url = Pluf::f('url_base')
|
||||
.Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
|
||||
array($request->project->shortname,
|
||||
$this->id));
|
||||
$title = sprintf(__('%s: Download %d added - %s'),
|
||||
Pluf_esc($request->project->name),
|
||||
$this->id, Pluf_esc($this->summary));
|
||||
$content = Pluf_esc($this->summary);
|
||||
$request->project->name,
|
||||
$this->id, $this->summary);
|
||||
$date = Pluf_Date::gmDateToGmString($this->creation_dtime);
|
||||
return Pluf_Translation::sprintf($base,
|
||||
array('url' => $url,
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'date' => $date));
|
||||
$context = new Pluf_Template_Context_Request(
|
||||
$request,
|
||||
array('url' => $url,
|
||||
'title' => $title,
|
||||
'file' => $this,
|
||||
'date' => $date)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/downloads/feedfragment.xml');
|
||||
return $tmpl->render($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification of change of the object.
|
||||
*
|
||||
* @param IDF_Conf Current configuration
|
||||
* @param bool Creation (true)
|
||||
*/
|
||||
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]);
|
||||
|
||||
$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);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'),
|
||||
$conf->getVal('downloads_notification_email'),
|
||||
sprintf(__('New download - %s (%s)'),
|
||||
$this->summary,
|
||||
$this->get_project()->shortname));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
|
||||
Pluf_Translation::loadSetLocale($current_locale);
|
||||
}
|
||||
}
|
@@ -183,6 +183,8 @@ class IDF_Views
|
||||
* email is available in the database, send an email with a key to
|
||||
* reset the password.
|
||||
*
|
||||
* If the user is not yet confirmed, send the confirmation key one
|
||||
* more time.
|
||||
*/
|
||||
function passwordRecoveryAsk($request, $match)
|
||||
{
|
||||
@@ -190,8 +192,7 @@ class IDF_Views
|
||||
if ($request->method == 'POST') {
|
||||
$form = new IDF_Form_Password($request->POST);
|
||||
if ($form->isValid()) {
|
||||
$form->save();
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryInputCode');
|
||||
$url = $form->save();
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
|
@@ -39,7 +39,7 @@ class IDF_Views_Admin
|
||||
public $home_precond = array('Pluf_Precondition::staffRequired');
|
||||
public function home($request, $match)
|
||||
{
|
||||
$title = __('Administer');
|
||||
$title = __('Forge Management');
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/gadmin/home.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
@@ -64,9 +64,11 @@ class IDF_Views_Admin
|
||||
$list_display = array(
|
||||
'shortname' => __('Short Name'),
|
||||
'name' => __('Name'),
|
||||
array('id', 'IDF_Views_Admin_projectSize', __('Repository Size')),
|
||||
);
|
||||
$pag->configure($list_display, array(),
|
||||
array('shortname'));
|
||||
$pag->extra_classes = array('', '', 'right');
|
||||
$pag->items_per_page = 25;
|
||||
$pag->no_results_text = __('No projects were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@@ -74,6 +76,7 @@ class IDF_Views_Admin
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'projects' => $pag,
|
||||
'size' => IDF_Views_Admin_getForgeSize(),
|
||||
),
|
||||
$request);
|
||||
}
|
||||
@@ -189,13 +192,14 @@ class IDF_Views_Admin
|
||||
if ($not_validated) {
|
||||
$pag->forced_where = new Pluf_SQL('first_name = \'---\' AND active!='.$true);
|
||||
$title = __('Not Validated User List');
|
||||
$pag->action = 'IDF_Views_Admin::usersNotValidated';
|
||||
} else {
|
||||
$pag->forced_where = new Pluf_SQL('first_name != \'---\'');
|
||||
$title = __('User List');
|
||||
$pag->action = 'IDF_Views_Admin::users';
|
||||
}
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->summary = __('This table shows the users in the forge.');
|
||||
$pag->action = 'IDF_Views_Admin::users';
|
||||
$pag->edit_action = array('IDF_Views_Admin::userUpdate', 'id');
|
||||
$pag->sort_order = array('login', 'ASC');
|
||||
$list_display = array(
|
||||
@@ -207,7 +211,9 @@ class IDF_Views_Admin
|
||||
array('last_login', 'Pluf_Paginator_DateYMDHM', __('Last Login')),
|
||||
);
|
||||
$pag->extra_classes = array('', '', 'a-c', 'a-c', 'a-c', 'a-c');
|
||||
$pag->configure($list_display, array(), array('login', 'last_login'));
|
||||
$pag->configure($list_display,
|
||||
array('login', 'last_name', 'email'),
|
||||
array('login', 'last_login'));
|
||||
$pag->items_per_page = 50;
|
||||
$pag->no_results_text = __('No users were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@@ -276,6 +282,38 @@ class IDF_Views_Admin
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user.
|
||||
*
|
||||
* Only staff can add a user. The user can be added together with
|
||||
* a public ssh key.
|
||||
*/
|
||||
public $userCreate_precond = array('Pluf_Precondition::staffRequired');
|
||||
public function userCreate($request, $match)
|
||||
{
|
||||
$params = array(
|
||||
'request' => $request,
|
||||
);
|
||||
if ($request->method == 'POST') {
|
||||
$form = new IDF_Form_Admin_UserCreate($request->POST, $params);
|
||||
if ($form->isValid()) {
|
||||
$cuser = $form->save();
|
||||
$request->user->setMessage(sprintf(__('The user %s has been created.'), (string) $cuser));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Admin::users');
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
$form = new IDF_Form_Admin_UserCreate(null, $params);
|
||||
}
|
||||
$title = __('Add User');
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/gadmin/users/create.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'form' => $form,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
}
|
||||
|
||||
function IDF_Views_Admin_bool($field, $item)
|
||||
@@ -283,4 +321,90 @@ function IDF_Views_Admin_bool($field, $item)
|
||||
$img = ($item->$field) ? 'day' : 'night';
|
||||
$text = ($item->$field) ? __('Yes') : __('No');
|
||||
return sprintf('<img src="'.Pluf::f('url_media').'/idf/img/%s.png" alt="%s" /> ', $img, $text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the size of the project.
|
||||
*
|
||||
* @param string Field
|
||||
* @param IDF_Project
|
||||
* @return string
|
||||
*/
|
||||
function IDF_Views_Admin_projectSize($field, $project)
|
||||
{
|
||||
$size = $project->getRepositorySize();
|
||||
if ($size == -1) {
|
||||
return '';
|
||||
}
|
||||
return Pluf_Utils::prettySize($size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a forge size.
|
||||
*
|
||||
* @return array Associative array with the size of each element
|
||||
*/
|
||||
function IDF_Views_Admin_getForgeSize()
|
||||
{
|
||||
$res = array();
|
||||
$res['repositories'] = 0;
|
||||
foreach (Pluf::factory('IDF_Project')->getList() as $prj) {
|
||||
$size = $prj->getRepositorySize();
|
||||
if ($size != -1) {
|
||||
$res['repositories'] += $size;
|
||||
}
|
||||
}
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').'du -sk '
|
||||
.escapeshellarg(Pluf::f('upload_path'));
|
||||
$out = explode(' ', shell_exec($cmd), 2);
|
||||
$res['downloads'] = $out[0]*1024;
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').'du -sk '
|
||||
.escapeshellarg(Pluf::f('upload_issue_path'));
|
||||
$out = explode(' ', shell_exec($cmd), 2);
|
||||
$res['attachments'] = $out[0]*1024;
|
||||
$res['database'] = IDF_Views_Admin_getForgeDbSize();
|
||||
$res['total'] = $res['repositories'] + $res['downloads'] + $res['attachments'] + $res['database'];
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database size as given by the database.
|
||||
*
|
||||
* @return int Database size
|
||||
*/
|
||||
function IDF_Views_Admin_getForgeDbSize()
|
||||
{
|
||||
$db = Pluf::db();
|
||||
if (Pluf::f('db_engine') == 'SQLite') {
|
||||
return filesize(Pluf::f('db_database'));
|
||||
}
|
||||
switch (Pluf::f('db_engine')) {
|
||||
case 'PostgreSQL':
|
||||
$sql = 'SELECT relname, pg_total_relation_size(CAST(relname AS
|
||||
TEXT)) AS size FROM pg_class AS pgc, pg_namespace AS pgn
|
||||
WHERE pg_table_is_visible(pgc.oid) IS TRUE AND relkind = \'r\'
|
||||
AND pgc.relnamespace = pgn.oid
|
||||
AND pgn.nspname NOT IN (\'information_schema\', \'pg_catalog\')';
|
||||
break;
|
||||
case 'MySQL':
|
||||
default:
|
||||
$sql = 'SHOW TABLE STATUS FROM `'.Pluf::f('db_database').'`';
|
||||
break;
|
||||
}
|
||||
$rs = $db->select($sql);
|
||||
$total = 0;
|
||||
switch (Pluf::f('db_engine')) {
|
||||
case 'PostgreSQL':
|
||||
foreach ($rs as $table) {
|
||||
$total += $table['size'];
|
||||
}
|
||||
break;
|
||||
case 'MySQL':
|
||||
default:
|
||||
foreach ($rs as $table) {
|
||||
$total += $table['Data_length'] + $table['Index_length'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
|
@@ -231,7 +231,7 @@ class IDF_Views_Download
|
||||
foreach ($st as $s) {
|
||||
$v = '';
|
||||
$d = '';
|
||||
$_s = split('=', $s, 2);
|
||||
$_s = explode('=', $s, 2);
|
||||
if (count($_s) > 1) {
|
||||
$v = trim($_s[0]);
|
||||
$d = trim($_s[1]);
|
||||
|
@@ -55,6 +55,7 @@ class IDF_Views_Issue
|
||||
$pag->action = array('IDF_Views_Issue::index', array($prj->shortname));
|
||||
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
||||
$pag->sort_reverse_order = array('modif_dtime');
|
||||
$pag->sort_link_title = true;
|
||||
$pag->extra_classes = array('a-c', '', 'a-c', '');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
@@ -62,7 +63,7 @@ class IDF_Views_Issue
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@@ -131,6 +132,7 @@ class IDF_Views_Issue
|
||||
$pag->action = array('IDF_Views_Issue::myIssues', array($prj->shortname, $match[2]));
|
||||
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
||||
$pag->sort_reverse_order = array('modif_dtime');
|
||||
$pag->sort_link_title = true;
|
||||
$pag->extra_classes = array('a-c', '', 'a-c', '');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
@@ -138,7 +140,7 @@ class IDF_Views_Issue
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@@ -171,36 +173,11 @@ class IDF_Views_Issue
|
||||
$params);
|
||||
if (!isset($request->POST['preview']) and $form->isValid()) {
|
||||
$issue = $form->save();
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
||||
array($prj->shortname));
|
||||
$urlissue = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||
array($prj->shortname, $issue->id));
|
||||
$request->user->setMessage(sprintf(__('<a href="%s">Issue %d</a> has been created.'), $urlissue, $issue->id));
|
||||
$to_emails = array();
|
||||
if (null != $issue->get_owner() and $issue->owner != $issue->submitter) {
|
||||
$to_emails[] = $issue->get_owner()->email;
|
||||
}
|
||||
if ('' != $request->conf->getVal('issues_notification_email', '')) {
|
||||
$to_emails[] = $request->conf->getVal('issues_notification_email', '');
|
||||
}
|
||||
foreach ($to_emails as $oemail) {
|
||||
$comments = $issue->get_comments_list(array('order' => 'id ASC'));
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'issue' => $issue,
|
||||
'comment' => $comments[0],
|
||||
'project' => $prj,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $oemail,
|
||||
sprintf(__('Issue %s - %s (%s)'),
|
||||
$issue->id, $issue->summary, $prj->shortname));
|
||||
$tmpl = new Pluf_Template('idf/issues/issue-created-email.txt');
|
||||
$email->addTextMessage($tmpl->render($context));
|
||||
$email->sendMail();
|
||||
}
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||
array($prj->shortname, $issue->id));
|
||||
$issue->notify($request->conf);
|
||||
if ($api) return $issue;
|
||||
$request->user->setMessage(sprintf(__('<a href="%s">Issue %d</a> has been created.'), $url, $issue->id));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
@@ -290,50 +267,12 @@ class IDF_Views_Issue
|
||||
$request->FILES),
|
||||
$params);
|
||||
if (!isset($request->POST['preview']) && $form->isValid()) {
|
||||
$issue = $form->save();
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
||||
array($prj->shortname));
|
||||
$urlissue = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||
array($prj->shortname, $issue->id));
|
||||
$request->user->setMessage(sprintf(__('<a href="%s">Issue %d</a> has been updated.'), $urlissue, $issue->id));
|
||||
// Get the list of interested person + owner + submitter
|
||||
if (!Pluf_Model_InArray($issue->get_submitter(), $interested)) {
|
||||
$interested[] = $issue->get_submitter();
|
||||
}
|
||||
if (null != $issue->get_owner() and
|
||||
!Pluf_Model_InArray($issue->get_owner(), $interested)) {
|
||||
$interested[] = $issue->get_owner();
|
||||
}
|
||||
$issue = $form->save(); // Note, should return the
|
||||
// last comment
|
||||
$issue->notify($request->conf, false);
|
||||
$comments = $issue->get_comments_list(array('order' => 'id DESC'));
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'issue' => $issue,
|
||||
'comments' => $comments,
|
||||
'project' => $prj,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/issues/issue-updated-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail_Batch(Pluf::f('from_email'));
|
||||
$to_emails = array();
|
||||
foreach ($interested as $user) {
|
||||
if ($user->id != $request->user->id) {
|
||||
$to_emails[] = $user->email;
|
||||
}
|
||||
}
|
||||
if ('' != $request->conf->getVal('issues_notification_email', '')) {
|
||||
$to_emails[] = $request->conf->getVal('issues_notification_email');
|
||||
}
|
||||
foreach ($to_emails as $oemail) {
|
||||
$email->setSubject(sprintf(__('Updated Issue %s - %s (%s)'),
|
||||
$issue->id, $issue->summary, $prj->shortname));
|
||||
$email->setTo($oemail);
|
||||
$email->setReturnPath(Pluf::f('from_email'));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
}
|
||||
$email->close();
|
||||
$url .= '#ic' . $comments[0]->id;
|
||||
$request->user->setMessage(sprintf(__('<a href="%s">Issue %d</a> has been updated.'), $url, $issue->id));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
@@ -436,6 +375,7 @@ class IDF_Views_Issue
|
||||
$pag->action = array('IDF_Views_Issue::listStatus', array($prj->shortname, $status));
|
||||
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
||||
$pag->sort_reverse_order = array('modif_dtime');
|
||||
$pag->sort_link_title = true;
|
||||
$pag->extra_classes = array('a-c', '', 'a-c', '');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
@@ -443,7 +383,7 @@ class IDF_Views_Issue
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@@ -494,6 +434,7 @@ class IDF_Views_Issue
|
||||
$pag->action = array('IDF_Views_Issue::listLabel', array($prj->shortname, $tag->id, $status));
|
||||
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
||||
$pag->sort_reverse_order = array('modif_dtime');
|
||||
$pag->sort_link_title = true;
|
||||
$pag->extra_classes = array('a-c', '', 'a-c', '');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
@@ -501,7 +442,7 @@ class IDF_Views_Issue
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('status', 'modif_dtime'));
|
||||
$pag->configure($list_display, array(), array('id', 'status', 'modif_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
@@ -565,7 +506,7 @@ class IDF_Views_Issue
|
||||
foreach ($st as $s) {
|
||||
$v = '';
|
||||
$d = '';
|
||||
$_s = split('=', $s, 2);
|
||||
$_s = explode('=', $s, 2);
|
||||
if (count($_s) > 1) {
|
||||
$v = trim($_s[0]);
|
||||
$d = trim($_s[1]);
|
||||
|
@@ -92,6 +92,10 @@ class IDF_Views_Project
|
||||
$rights[] = '\'IDF_WikiPage\'';
|
||||
$rights[] = '\'IDF_WikiRevision\'';
|
||||
}
|
||||
if (true === IDF_Precondition::accessReview($request)) {
|
||||
$rights[] = '\'IDF_Review_Comment\'';
|
||||
$rights[] = '\'IDF_Review_Patch\'';
|
||||
}
|
||||
if (count($rights) == 0) {
|
||||
$rights[] = '\'IDF_Dummy\'';
|
||||
}
|
||||
@@ -120,7 +124,7 @@ class IDF_Views_Project
|
||||
$tags = IDF_Views_Wiki::getWikiTags($prj);
|
||||
$pages = $tags[0]->get_idf_wikipage_list();
|
||||
}
|
||||
if (!$request->user->isAnonymous()) {
|
||||
if (!$request->user->isAnonymous() and $prj->isRestricted()) {
|
||||
$feedurl = Pluf_HTTP_URL_urlForView('idf_project_timeline_feed_auth',
|
||||
array($prj->shortname,
|
||||
IDF_Precondition::genFeedToken($prj, $request->user)));
|
||||
@@ -169,6 +173,10 @@ class IDF_Views_Project
|
||||
$rights[] = '\'IDF_WikiPage\'';
|
||||
$rights[] = '\'IDF_WikiRevision\'';
|
||||
}
|
||||
if (true === IDF_Precondition::accessReview($request)) {
|
||||
$rights[] = '\'IDF_Review_Comment\'';
|
||||
$rights[] = '\'IDF_Review_Patch\'';
|
||||
}
|
||||
if (count($rights) == 0) {
|
||||
$rights[] = '\'IDF_Dummy\'';
|
||||
}
|
||||
@@ -177,14 +185,21 @@ class IDF_Views_Project
|
||||
$params = array(
|
||||
'filter' => $sql->gen(),
|
||||
'order' => 'creation_dtime DESC',
|
||||
'nb' => 50,
|
||||
'nb' => 20,
|
||||
);
|
||||
$items = Pluf::factory('IDF_Timeline')->getList($params);
|
||||
$set = new Pluf_Model_Set($items,
|
||||
array('public_dtime' => 'public_dtime'));
|
||||
$out = array();
|
||||
foreach ($set as $item) {
|
||||
$out[] = $item->feedFragment($request);
|
||||
if ($item->id) {
|
||||
$out[] = $item->feedFragment($request);
|
||||
}
|
||||
}
|
||||
if ($items->count() > 0) {
|
||||
$date = Pluf_Date::gmDateToGmString($items[0]->creation_dtime);
|
||||
} else {
|
||||
$date = gmdate('c');
|
||||
}
|
||||
$out = Pluf_Template::markSafe(implode("\n", $out));
|
||||
$tmpl = new Pluf_Template('idf/index.atom');
|
||||
@@ -194,6 +209,7 @@ class IDF_Views_Project
|
||||
array($prj->shortname));
|
||||
$context = new Pluf_Template_Context_Request($request,
|
||||
array('body' => $out,
|
||||
'date' => $date,
|
||||
'title' => $title,
|
||||
'feedurl' => $feedurl,
|
||||
'viewurl' => $viewurl));
|
||||
@@ -342,7 +358,7 @@ class IDF_Views_Project
|
||||
$conf->setVal($key, $val);
|
||||
}
|
||||
$request->user->setMessage(__('The documentation configuration has been saved.'));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Project::adminDownloads',
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Project::adminWiki',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
@@ -510,6 +526,7 @@ class IDF_Views_Project
|
||||
'remote_svn' => $remote_svn,
|
||||
'repository_access' => $prj->getRemoteAccessUrl(),
|
||||
'repository_type' => $repository_type,
|
||||
'repository_size' => $prj->getRepositorySize(),
|
||||
'page_title' => $title,
|
||||
'form' => $form,
|
||||
),
|
||||
|
@@ -150,72 +150,39 @@ class IDF_Views_Review
|
||||
array('files' => $diff->files,
|
||||
'user' => $request->user,
|
||||
'patch' => $patch,
|
||||
'project' => $prj,
|
||||
));
|
||||
if ($form->isValid()) {
|
||||
$patch = $form->save();
|
||||
$review_comment = $form->save();
|
||||
$review = $patch->get_review();
|
||||
$urlr = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
|
||||
array($prj->shortname, $review->id));
|
||||
$request->user->setMessage(sprintf(__('Your <a href="%s">code review %d</a> has been published.'), $urlr, $review->id));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::index',
|
||||
array($prj->shortname));
|
||||
// Get the list of reviewers + submitter
|
||||
$reviewers = $review->get_reviewers_list();
|
||||
if (!Pluf_Model_InArray($review->get_submitter(), $reviewers)) {
|
||||
$reviewers[] = $review->get_submitter();
|
||||
}
|
||||
$comments = $patch->get_filecomments_list(array('order' => 'id DESC'));
|
||||
$context = new Pluf_Template_Context(
|
||||
array(
|
||||
'review' => $review,
|
||||
'patch' => $patch,
|
||||
'comments' => $comments,
|
||||
'project' => $prj,
|
||||
'url_base' => Pluf::f('url_base'),
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/review/review-updated-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail_Batch(Pluf::f('from_email'));
|
||||
$to_emails = array();
|
||||
foreach ($reviewers as $user) {
|
||||
if ($user->id != $request->user->id) {
|
||||
$to_emails[] = $user->email;
|
||||
}
|
||||
}
|
||||
if ('' != $request->conf->getVal('review_notification_email', '')) {
|
||||
$to_emails[] = $request->conf->getVal('review_notification_email');
|
||||
}
|
||||
foreach ($to_emails as $oemail) {
|
||||
$email->setSubject(sprintf(__('Updated Code Review %s - %s (%s)'),
|
||||
$review->id, $review->summary, $prj->shortname));
|
||||
$email->setTo($oemail);
|
||||
$email->setReturnPath(Pluf::f('from_email'));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
}
|
||||
$email->close();
|
||||
$review_comment->notify($request->conf);
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
$form = new IDF_Form_ReviewFileComment(null,
|
||||
array('files' => $diff->files,
|
||||
'user' => $request->user,
|
||||
'project' => $prj,
|
||||
'patch' => $patch,));
|
||||
}
|
||||
$scm = IDF_Scm::get($request->project);
|
||||
$files = array();
|
||||
$reviewers = array();
|
||||
foreach ($diff->files as $filename => $def) {
|
||||
$fileinfo = $scm->getFileInfo($filename, $patch->get_commit()->scm_id);
|
||||
$fileinfo = $scm->getPathInfo($filename, $patch->get_commit()->scm_id);
|
||||
$sql = new Pluf_SQL('cfile=%s', array($filename));
|
||||
$cts = $patch->get_filecomments_list(array('filter'=>$sql->gen(),
|
||||
'order'=>'creation_dtime ASC'));
|
||||
$cts = $patch->getFileComments(array('filter'=>$sql->gen(),
|
||||
'order'=>'creation_dtime ASC'));
|
||||
foreach ($cts as $ct) {
|
||||
$reviewers[] = $ct->get_submitter();
|
||||
$reviewers[] = $ct->get_comment()->get_submitter();
|
||||
}
|
||||
if (count($def['chunks'])) {
|
||||
$orig_file = ($fileinfo) ? $scm->getBlob($fileinfo) : '';
|
||||
$orig_file = ($fileinfo) ? $scm->getFile($fileinfo) : '';
|
||||
$files[$filename] = array(
|
||||
$diff->fileCompare($orig_file, $def, $filename),
|
||||
$form->f->{md5($filename)},
|
||||
@@ -227,15 +194,19 @@ class IDF_Views_Review
|
||||
}
|
||||
$reviewers = Pluf_Model_RemoveDuplicates($reviewers);
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/review/view.html',
|
||||
array_merge(
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'review' => $review,
|
||||
'files' => $files,
|
||||
'diff' => $diff,
|
||||
'patch' => $patch,
|
||||
'comments' => $patch->get_comments_list(array('sort' => 'id ASC')),
|
||||
'form' => $form,
|
||||
'reviewers' => $reviewers,
|
||||
),
|
||||
IDF_Views_Issue::autoCompleteArrays($prj)
|
||||
),
|
||||
$request);
|
||||
}
|
||||
}
|
||||
|
@@ -34,11 +34,12 @@ class IDF_Views_Source
|
||||
/**
|
||||
* Extension supported by the syntax highlighter.
|
||||
*/
|
||||
public static $supportedExtenstions = array('c', 'cc', 'cpp', 'cs', 'css',
|
||||
'cyc', 'java', 'bsh', 'csh',
|
||||
'sh', 'cv', 'py', 'perl', 'php',
|
||||
'pl', 'pm', 'rb', 'js', 'html',
|
||||
'html', 'xhtml', 'xml', 'xsl');
|
||||
public static $supportedExtenstions = array(
|
||||
'ascx', 'ashx', 'asmx', 'aspx', 'browser', 'bsh', 'c', 'cc',
|
||||
'config', 'cpp', 'cs', 'csh', 'csproj', 'css', 'cv', 'cyc',
|
||||
'html', 'html', 'java', 'js', 'master', 'perl', 'php', 'pl',
|
||||
'pm', 'py', 'rb', 'sh', 'sitemap', 'skin', 'sln', 'svc', 'vala',
|
||||
'vb', 'vbproj', 'wsdl', 'xhtml', 'xml', 'xsd', 'xsl', 'xslt');
|
||||
|
||||
/**
|
||||
* Display help on how to checkout etc.
|
||||
@@ -61,9 +62,12 @@ class IDF_Views_Source
|
||||
public $changeLog_precond = array('IDF_Precondition::accessSource');
|
||||
public function changeLog($request, $match)
|
||||
{
|
||||
$title = sprintf(__('%1$s %2$s Change Log'), (string) $request->project,
|
||||
$this->getScmType($request));
|
||||
$scm = IDF_Scm::get($request->project);
|
||||
if (!$scm->isAvailable()) {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::help',
|
||||
array($request->project->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$branches = $scm->getBranches();
|
||||
$commit = $match[2];
|
||||
if (!$scm->isValidRevision($commit)) {
|
||||
@@ -76,9 +80,11 @@ class IDF_Views_Source
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::changeLog',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
$scm->getMainBranch()));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$title = sprintf(__('%1$s %2$s Change Log'), (string) $request->project,
|
||||
$this->getScmType($request));
|
||||
$changes = $scm->getChangeLog($commit, 25);
|
||||
$rchanges = array();
|
||||
// Sync with the database
|
||||
@@ -87,13 +93,19 @@ class IDF_Views_Source
|
||||
}
|
||||
$rchanges = new Pluf_Template_ContextVars($rchanges);
|
||||
$scmConf = $request->conf->getVal('scm', 'git');
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/source/changelog.html',
|
||||
$in_branches = $scm->inBranches($commit, '');
|
||||
$tags = $scm->getTags();
|
||||
$in_tags = $scm->inTags($commit, '');
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/source/'.$scmConf.'/changelog.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'title' => $title,
|
||||
'changes' => $rchanges,
|
||||
'commit' => $commit,
|
||||
'branches' => $branches,
|
||||
'tree_in' => $in_branches,
|
||||
'tags' => $tags,
|
||||
'tags_in' => $in_tags,
|
||||
'scm' => $scmConf,
|
||||
),
|
||||
$request);
|
||||
@@ -102,8 +114,6 @@ class IDF_Views_Source
|
||||
public $treeBase_precond = array('IDF_Precondition::accessSource');
|
||||
public function treeBase($request, $match)
|
||||
{
|
||||
$title = sprintf(__('%1$s %2$s Source Tree'),
|
||||
$request->project, $this->getScmType($request));
|
||||
$scm = IDF_Scm::get($request->project);
|
||||
if (!$scm->isAvailable()) {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::help',
|
||||
@@ -118,8 +128,12 @@ class IDF_Views_Source
|
||||
$scm->getMainBranch()));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$title = sprintf(__('%1$s %2$s Source Tree'),
|
||||
$request->project, $this->getScmType($request));
|
||||
$branches = $scm->getBranches();
|
||||
$in_branches = $scm->inBranches($commit, '');
|
||||
$tags = $scm->getTags();
|
||||
$in_tags = $scm->inTags($commit, '');
|
||||
$cache = Pluf_Cache::factory();
|
||||
$key = sprintf('Project:%s::IDF_Views_Source::treeBase:%s::',
|
||||
$request->project->id, $commit);
|
||||
@@ -127,7 +141,6 @@ class IDF_Views_Source
|
||||
$res = new Pluf_Template_ContextVars($scm->getTree($commit));
|
||||
$cache->set($key, $res);
|
||||
}
|
||||
//$tree_in = in_array($commit, $branches);
|
||||
$scmConf = $request->conf->getVal('scm', 'git');
|
||||
$props = $scm->getProperties($commit);
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/source/'.$scmConf.'/tree.html',
|
||||
@@ -139,6 +152,8 @@ class IDF_Views_Source
|
||||
'commit' => $commit,
|
||||
'tree_in' => $in_branches,
|
||||
'branches' => $branches,
|
||||
'tags' => $tags,
|
||||
'tags_in' => $in_tags,
|
||||
'props' => $props,
|
||||
),
|
||||
$request);
|
||||
@@ -147,22 +162,18 @@ class IDF_Views_Source
|
||||
public $tree_precond = array('IDF_Precondition::accessSource');
|
||||
public function tree($request, $match)
|
||||
{
|
||||
$title = sprintf(__('%1$s %2$s Source Tree'),
|
||||
$request->project, $this->getScmType($request));
|
||||
$scm = IDF_Scm::get($request->project);
|
||||
$commit = $match[2];
|
||||
|
||||
if (!$scm->isAvailable()) {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::help',
|
||||
array($request->project->shortname));
|
||||
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
|
||||
$branches = $scm->getBranches();
|
||||
$commit = $match[2];
|
||||
$request_file = $match[3];
|
||||
$fburl = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$scm->getMainBranch()));
|
||||
$request_file = $match[3];
|
||||
if (substr($request_file, -1) == '/') {
|
||||
$request_file = substr($request_file, 0, -1);
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::tree',
|
||||
@@ -170,23 +181,21 @@ class IDF_Views_Source
|
||||
$request_file));
|
||||
return new Pluf_HTTP_Response_Redirect($url, 301);
|
||||
}
|
||||
|
||||
if (!$scm->isValidRevision($commit, $request_file)) {
|
||||
// Redirect to the first branch
|
||||
return new Pluf_HTTP_Response_Redirect($fburl);
|
||||
}
|
||||
|
||||
$request_file_info = $scm->getPathInfo($request_file, $commit);
|
||||
if (!$request_file_info) {
|
||||
// Redirect to the first branch
|
||||
return new Pluf_HTTP_Response_Redirect($fburl);
|
||||
}
|
||||
|
||||
$branches = $scm->getBranches();
|
||||
$tags = $scm->getTags();
|
||||
if ($request_file_info->type != 'tree') {
|
||||
$info = self::getRequestedFileMimeType($request_file_info,
|
||||
$info = self::getRequestedFileMimeType($request_file_info,
|
||||
$commit, $scm);
|
||||
if (!self::isText($info)) {
|
||||
|
||||
$rep = new Pluf_HTTP_Response($scm->getFile($request_file_info),
|
||||
$info[0]);
|
||||
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$info[1].'"';
|
||||
@@ -194,6 +203,7 @@ class IDF_Views_Source
|
||||
} else {
|
||||
// We want to display the content of the file as text
|
||||
$extra = array('branches' => $branches,
|
||||
'tags' => $tags,
|
||||
'commit' => $commit,
|
||||
'request_file' => $request_file,
|
||||
'request_file_info' => $request_file_info,
|
||||
@@ -203,32 +213,34 @@ class IDF_Views_Source
|
||||
}
|
||||
}
|
||||
|
||||
$bc = self::makeBreadCrumb($request->project, $commit, $request_file_info->file);
|
||||
$bc = self::makeBreadCrumb($request->project, $commit, $request_file_info->fullpath);
|
||||
$title = sprintf(__('%1$s %2$s Source Tree'),
|
||||
$request->project, $this->getScmType($request));
|
||||
|
||||
$page_title = $bc.' - '.$title;
|
||||
$cobject = $scm->getCommit($commit);
|
||||
if (!$cobject) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$scm->getMainBranch()));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$in_branches = $scm->inBranches($commit, $request_file);
|
||||
try {
|
||||
$cache = Pluf_Cache::factory();
|
||||
$key = sprintf('Project:%s::IDF_Views_Source::tree:%s::%s',
|
||||
$request->project->id, $commit, $request_file);
|
||||
if (null === ($res=$cache->get($key))) {
|
||||
$res = new Pluf_Template_ContextVars($scm->getTree($commit, $request_file));
|
||||
$cache->set($key, $res);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
throw $e;
|
||||
$in_tags = $scm->inTags($commit, $request_file);
|
||||
$cache = Pluf_Cache::factory();
|
||||
$key = sprintf('Project:%s::IDF_Views_Source::tree:%s::%s',
|
||||
$request->project->id, $commit, $request_file);
|
||||
if (null === ($res=$cache->get($key))) {
|
||||
$res = new Pluf_Template_ContextVars($scm->getTree($commit, $request_file));
|
||||
$cache->set($key, $res);
|
||||
}
|
||||
// try to find the previous level if it exists.
|
||||
$prev = split('/', $request_file);
|
||||
$prev = explode('/', $request_file);
|
||||
$l = array_pop($prev);
|
||||
$previous = substr($request_file, 0, -strlen($l.' '));
|
||||
$scmConf = $request->conf->getVal('scm', 'git');
|
||||
$props = null;
|
||||
if ($scmConf === 'svn') {
|
||||
$props = $scm->getProperties($commit, $request_file);
|
||||
}
|
||||
$props = $scm->getProperties($commit, $request_file);
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/source/'.$scmConf.'/tree.html',
|
||||
array(
|
||||
'page_title' => $page_title,
|
||||
@@ -241,6 +253,8 @@ class IDF_Views_Source
|
||||
'prev' => $previous,
|
||||
'tree_in' => $in_branches,
|
||||
'branches' => $branches,
|
||||
'tags' => $tags,
|
||||
'tags_in' => $in_tags,
|
||||
'props' => $props,
|
||||
),
|
||||
$request);
|
||||
@@ -248,12 +262,12 @@ class IDF_Views_Source
|
||||
|
||||
public static function makeBreadCrumb($project, $commit, $file, $sep='/')
|
||||
{
|
||||
$elts = split('/', $file);
|
||||
$elts = explode('/', $file);
|
||||
$out = array();
|
||||
$stack = '';
|
||||
$i = 0;
|
||||
foreach ($elts as $elt) {
|
||||
$stack .= ($i==0) ? $elt : '/'.$elt;
|
||||
$stack .= ($i==0) ? rawurlencode($elt) : '/'.rawurlencode($elt);
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::tree',
|
||||
array($project->shortname,
|
||||
$commit, $stack));
|
||||
@@ -268,22 +282,32 @@ class IDF_Views_Source
|
||||
{
|
||||
$scm = IDF_Scm::get($request->project);
|
||||
$commit = $match[2];
|
||||
$branches = $scm->getBranches();
|
||||
if (!$scm->isValidRevision($commit)) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
$scm->getMainBranch()));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$large = $scm->isCommitLarge($commit);
|
||||
$cobject = $scm->getCommit($commit, !$large);
|
||||
if (!$cobject) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$scm->getMainBranch()));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$title = sprintf(__('%s Commit Details'), (string) $request->project);
|
||||
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
|
||||
$large = $scm->isCommitLarge($commit);
|
||||
$cobject = $scm->getCommit($commit, !$large);
|
||||
$rcommit = IDF_Commit::getOrAdd($cobject, $request->project);
|
||||
$diff = new IDF_Diff($cobject->changes);
|
||||
$diff->parse();
|
||||
$scmConf = $request->conf->getVal('scm', 'git');
|
||||
$branches = $scm->getBranches();
|
||||
$in_branches = $scm->inBranches($cobject->commit, '');
|
||||
$tags = $scm->getTags();
|
||||
$in_tags = $scm->inTags($cobject->commit, '');
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/source/commit.html',
|
||||
array(
|
||||
'page_title' => $page_title,
|
||||
@@ -292,6 +316,9 @@ class IDF_Views_Source
|
||||
'cobject' => $cobject,
|
||||
'commit' => $commit,
|
||||
'branches' => $branches,
|
||||
'tree_in' => $in_branches,
|
||||
'tags' => $tags,
|
||||
'tags_in' => $in_tags,
|
||||
'scm' => $scmConf,
|
||||
'rcommit' => $rcommit,
|
||||
'large_commit' => $large,
|
||||
@@ -304,12 +331,11 @@ class IDF_Views_Source
|
||||
{
|
||||
$scm = IDF_Scm::get($request->project);
|
||||
$commit = $match[2];
|
||||
$branches = $scm->getBranches();
|
||||
if (!$scm->isValidRevision($commit)) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
$scm->getMainBranch()));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$cobject = $scm->getCommit($commit, true);
|
||||
@@ -327,22 +353,21 @@ class IDF_Views_Source
|
||||
$this->getScmType($request));
|
||||
$scm = IDF_Scm::get($request->project);
|
||||
$branches = $extra['branches'];
|
||||
$tags = $extra['tags'];
|
||||
$commit = $extra['commit'];
|
||||
$request_file = $extra['request_file'];
|
||||
$request_file_info = $extra['request_file_info'];
|
||||
$bc = self::makeBreadCrumb($request->project, $commit, $request_file_info->file);
|
||||
$bc = self::makeBreadCrumb($request->project, $commit, $request_file_info->fullpath);
|
||||
$page_title = $bc.' - '.$title;
|
||||
$cobject = $scm->getCommit($commit);
|
||||
$tree_in = in_array($commit, $branches);
|
||||
$in_branches = $scm->inBranches($commit, $request_file);
|
||||
$in_tags = $scm->inTags($commit, '');
|
||||
// try to find the previous level if it exists.
|
||||
$prev = split('/', $request_file);
|
||||
$prev = explode('/', $request_file);
|
||||
$l = array_pop($prev);
|
||||
$previous = substr($request_file, 0, -strlen($l.' '));
|
||||
$scmConf = $request->conf->getVal('scm', 'git');
|
||||
$props = null;
|
||||
if ($scmConf === 'svn') {
|
||||
$props = $scm->getProperties($commit, $request_file);
|
||||
}
|
||||
$props = $scm->getProperties($commit, $request_file);
|
||||
$content = self::highLight($extra['mime'], $scm->getFile($request_file_info));
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/source/'.$scmConf.'/file.html',
|
||||
array(
|
||||
@@ -353,10 +378,13 @@ class IDF_Views_Source
|
||||
'commit' => $commit,
|
||||
'cobject' => $cobject,
|
||||
'fullpath' => $request_file,
|
||||
'efullpath' => IDF_Scm::smartEncode($request_file),
|
||||
'base' => $request_file_info->file,
|
||||
'prev' => $previous,
|
||||
'tree_in' => $tree_in,
|
||||
'tree_in' => $in_branches,
|
||||
'branches' => $branches,
|
||||
'tags' => $tags,
|
||||
'tags_in' => $in_tags,
|
||||
'props' => $props,
|
||||
),
|
||||
$request);
|
||||
@@ -370,14 +398,13 @@ class IDF_Views_Source
|
||||
public function getFile($request, $match)
|
||||
{
|
||||
$scm = IDF_Scm::get($request->project);
|
||||
$branches = $scm->getBranches();
|
||||
$commit = $match[2];
|
||||
$request_file = $match[3];
|
||||
if (!$scm->isValidRevision($commit)) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
$scm->getMainBranch()));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$request_file_info = $scm->getPathInfo($request_file, $commit);
|
||||
@@ -385,7 +412,7 @@ class IDF_Views_Source
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
$scm->getMainBranch()));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$info = self::getRequestedFileMimeType($request_file_info,
|
||||
@@ -405,12 +432,11 @@ class IDF_Views_Source
|
||||
{
|
||||
$commit = trim($match[2]);
|
||||
$scm = IDF_Scm::get($request->project);
|
||||
$branches = $scm->getBranches();
|
||||
if (!$scm->isValidRevision($commit)) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
$scm->getMainBranch()));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$base = $request->project->shortname.'-'.$commit;
|
||||
@@ -447,7 +473,7 @@ class IDF_Views_Source
|
||||
* @param string File content
|
||||
* @return array Mime type found or 'application/octet-stream', basename, extension
|
||||
*/
|
||||
public static function getMimeTypeFromContent($file, &$filedata)
|
||||
public static function getMimeTypeFromContent($file, $filedata)
|
||||
{
|
||||
$info = pathinfo($file);
|
||||
$res = array('application/octet-stream',
|
||||
|
@@ -113,8 +113,9 @@ class IDF_Views_User
|
||||
$form = new IDF_Form_UserAccount($request->POST, $params);
|
||||
if ($form->isValid()) {
|
||||
$user = $form->save();
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views::index');
|
||||
$request->user->setMessage(__('Your personal information have been updated.'));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_User::myAccount');
|
||||
$request->session->setData('pluf_language', $user->language);
|
||||
$request->user->setMessage(__('Your personal information has been updated.'));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
@@ -123,20 +124,35 @@ class IDF_Views_User
|
||||
$form = new IDF_Form_UserAccount($data, $params);
|
||||
}
|
||||
$keys = $request->user->get_idf_key_list();
|
||||
if ($keys->count() > 0 and strlen($keys[0]->content) > 30) {
|
||||
$ssh_key = Pluf_Template::markSafe('<span class="mono">'.Pluf_esc(substr($keys[0]->content, 0, 30)).'...</span><br /><span class="helptext">'.__('Troncated for security reasons.').'</span>');
|
||||
} else {
|
||||
$ssh_key = __('You have not upload your public SSH key yet.');
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/user/myaccount.html',
|
||||
array('page_title' => __('Your Account'),
|
||||
'api_key' => $api_key,
|
||||
'ext_pass' => $ext_pass,
|
||||
'ssh_key' => $ssh_key,
|
||||
'keys' => $keys,
|
||||
'form' => $form),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a SSH key.
|
||||
*
|
||||
* This is redirecting to the preferences
|
||||
*/
|
||||
public $deleteKey_precond = array('Pluf_Precondition::loginRequired');
|
||||
public function deleteKey($request, $match)
|
||||
{
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_User::myAccount');
|
||||
if ($request->method == 'POST') {
|
||||
$key = Pluf_Shortcuts_GetObjectOr404('IDF_Key', $match[1]);
|
||||
if ($key->user != $request->user->id) {
|
||||
return new Pluf_HTTP_Response_Forbidden($request);
|
||||
}
|
||||
$key->delete();
|
||||
$request->user->setMessage(__('The SSH key has been deleted.'));
|
||||
}
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter the key to change an email address.
|
||||
*
|
||||
@@ -191,7 +207,6 @@ class IDF_Views_User
|
||||
*/
|
||||
public function view($request, $match)
|
||||
{
|
||||
$projects = IDF_Views::getProjects($request->user);
|
||||
$sql = new Pluf_SQL('login=%s', array($match[1]));
|
||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||
if (count($users) != 1 or !$users[0]->active) {
|
||||
@@ -200,7 +215,6 @@ class IDF_Views_User
|
||||
return Pluf_Shortcuts_RenderToResponse('idf/user/public.html',
|
||||
array('page_title' => (string) $users[0],
|
||||
'member' => $users[0],
|
||||
'projects' => $projects,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
@@ -222,7 +222,7 @@ class IDF_Views_Wiki
|
||||
array($prj->id, $match[2]));
|
||||
$pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() != 1) {
|
||||
throw new Pluf_HTTP_Response_NotFound($request);
|
||||
return new Pluf_HTTP_Response_NotFound($request);
|
||||
}
|
||||
$page = $pages[0];
|
||||
$oldrev = false;
|
||||
@@ -231,7 +231,7 @@ class IDF_Views_Wiki
|
||||
$oldrev = Pluf_Shortcuts_GetObjectOr404('IDF_WikiRevision',
|
||||
$request->GET['rev']);
|
||||
if ($oldrev->wikipage != $page->id or $oldrev->is_head == true) {
|
||||
throw new Pluf_HTTP_Response_NotFound($request);
|
||||
return new Pluf_HTTP_Response_NotFound($request);
|
||||
}
|
||||
}
|
||||
$ptags = self::getWikiTags($prj);
|
||||
@@ -240,8 +240,7 @@ class IDF_Views_Wiki
|
||||
$dep = Pluf_Model_InArray($dtag, $tags);
|
||||
$title = $page->title;
|
||||
$revision = $page->get_current_revision();
|
||||
$db = $page->getDbConnection();
|
||||
$false = Pluf_DB_BooleanToDb(false, $db);
|
||||
$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',
|
||||
@@ -269,7 +268,7 @@ class IDF_Views_Wiki
|
||||
$page = $oldrev->get_wikipage();
|
||||
$prj->inOr404($page);
|
||||
if ($oldrev->is_head == true) {
|
||||
throw new Pluf_HTTP_Error404($request);
|
||||
return new Pluf_HTTP_Response_NotFound($request);
|
||||
}
|
||||
if ($request->method == 'POST') {
|
||||
$oldrev->delete();
|
||||
@@ -281,8 +280,7 @@ class IDF_Views_Wiki
|
||||
|
||||
$title = sprintf(__('Delete Old Revision of %s'), $page->title);
|
||||
$revision = $page->get_current_revision();
|
||||
$db = $page->getDbConnection();
|
||||
$false = Pluf_DB_BooleanToDb(false, $db);
|
||||
$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',
|
||||
@@ -310,7 +308,7 @@ class IDF_Views_Wiki
|
||||
array($prj->id, $match[2]));
|
||||
$pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() != 1) {
|
||||
throw new Pluf_HTTP_Error404($request);
|
||||
return new Pluf_HTTP_Response_NotFound($request);
|
||||
}
|
||||
$page = $pages[0];
|
||||
$title = sprintf(__('Update %s'), $page->title);
|
||||
@@ -348,6 +346,46 @@ class IDF_Views_Wiki
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a Wiki page.
|
||||
*/
|
||||
public $delete_precond = array('IDF_Precondition::accessWiki',
|
||||
'IDF_Precondition::projectMemberOrOwner');
|
||||
public function delete($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$page = Pluf_Shortcuts_GetObjectOr404('IDF_WikiPage', $match[2]);
|
||||
$prj->inOr404($page);
|
||||
$params = array('page' => $page);
|
||||
if ($request->method == 'POST') {
|
||||
$form = new IDF_Form_WikiDelete($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::index',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
$form = new IDF_Form_WikiDelete(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',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'page' => $page,
|
||||
'form' => $form,
|
||||
'rev' => $revision,
|
||||
'revs' => $revs,
|
||||
'tags' => $page->get_tags_list(),
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the wiki tags.
|
||||
*
|
||||
@@ -397,7 +435,7 @@ class IDF_Views_Wiki
|
||||
foreach ($st as $s) {
|
||||
$v = '';
|
||||
$d = '';
|
||||
$_s = split('=', $s, 2);
|
||||
$_s = explode('=', $s, 2);
|
||||
if (count($_s) > 1) {
|
||||
$v = trim($_s[0]);
|
||||
$d = trim($_s[1]);
|
||||
|
@@ -146,8 +146,7 @@ class IDF_WikiPage extends Pluf_Model
|
||||
|
||||
function get_current_revision()
|
||||
{
|
||||
$db = $this->getDbConnection();
|
||||
$true = Pluf_DB_BooleanToDb(true, $db);
|
||||
$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;
|
||||
@@ -196,35 +195,30 @@ class IDF_WikiPage extends Pluf_Model
|
||||
$user = $stag->start($this->get_submitter(), $request, '', false);
|
||||
$out .= sprintf(__('<a href="%1$s" title="View page">%2$s</a>, %3$s'), $url, Pluf_esc($this->title), Pluf_esc($this->summary)).'</td>';
|
||||
$out .= "\n".'<tr class="extra"><td colspan="2">
|
||||
<div class="helptext right">'.sprintf(__('Creation of <a href="%s">page %s</a>'), $url, Pluf_esc($this->title)).', '.__('by').' '.$user.'</div></td></tr>';
|
||||
<div class="helptext right">'.sprintf(__('Creation of <a href="%s">page %s</a>, by %s'), $url, Pluf_esc($this->title), $user).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
|
||||
public function feedFragment($request)
|
||||
{
|
||||
$base = '<entry>
|
||||
<title>%%title%%</title>
|
||||
<link href="%%url%%"/>
|
||||
<id>%%url%%</id>
|
||||
<updated>%%date%%</updated>
|
||||
<content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
|
||||
%%content%%
|
||||
</div></content>
|
||||
</entry>';
|
||||
$url = Pluf::f('url_base')
|
||||
.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
|
||||
array($request->project->shortname,
|
||||
$this->title));
|
||||
$title = sprintf(__('%s: Documentation page %s added - %s'),
|
||||
Pluf_esc($request->project->name),
|
||||
Pluf_esc($this->title), Pluf_esc($this->summary));
|
||||
$content = Pluf_esc($this->summary);
|
||||
$request->project->name,
|
||||
$this->title, $this->summary);
|
||||
$date = Pluf_Date::gmDateToGmString($this->creation_dtime);
|
||||
return Pluf_Translation::sprintf($base,
|
||||
array('url' => $url,
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'date' => $date));
|
||||
$context = new Pluf_Template_Context_Request(
|
||||
$request,
|
||||
array('url' => $url,
|
||||
'title' => $title,
|
||||
'page' => $this,
|
||||
'rev' => $this->get_current_revision(),
|
||||
'create' => true,
|
||||
'date' => $date)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/wiki/feedfragment.xml');
|
||||
return $tmpl->render($context);
|
||||
}
|
||||
|
||||
}
|
@@ -186,36 +186,97 @@ class IDF_WikiRevision extends Pluf_Model
|
||||
}
|
||||
$out .= '</td></tr>';
|
||||
$out .= "\n".'<tr class="extra"><td colspan="2">
|
||||
<div class="helptext right">'.sprintf(__('Change of <a href="%s">%s</a>'), $url, Pluf_esc($page->title)).', '.__('by').' '.$user.'</div></td></tr>';
|
||||
<div class="helptext right">'.sprintf(__('Change of <a href="%s">%s</a>, by %s'), $url, Pluf_esc($page->title), $user).'</div></td></tr>';
|
||||
return Pluf_Template::markSafe($out);
|
||||
}
|
||||
|
||||
public function feedFragment($request)
|
||||
{
|
||||
$base = '<entry>
|
||||
<title>%%title%%</title>
|
||||
<link href="%%url%%"/>
|
||||
<id>%%url%%</id>
|
||||
<updated>%%date%%</updated>
|
||||
<content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
|
||||
%%content%%
|
||||
</div></content>
|
||||
</entry>';
|
||||
$page = $this->get_wikipage();
|
||||
$url = Pluf::f('url_base')
|
||||
.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
|
||||
array($request->project->shortname,
|
||||
$page->title));
|
||||
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));
|
||||
}
|
||||
$title = sprintf(__('%s: Documentation page %s updated - %s'),
|
||||
Pluf_esc($request->project->name),
|
||||
Pluf_esc($page->title), Pluf_esc($page->summary));
|
||||
$content = Pluf_esc($this->summary);
|
||||
$request->project->name,
|
||||
$page->title, $page->summary);
|
||||
$date = Pluf_Date::gmDateToGmString($this->creation_dtime);
|
||||
return Pluf_Translation::sprintf($base,
|
||||
array('url' => $url,
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'date' => $date));
|
||||
$context = new Pluf_Template_Context_Request(
|
||||
$request,
|
||||
array('url' => $url,
|
||||
'title' => $title,
|
||||
'page' => $page,
|
||||
'rev' => $this,
|
||||
'create' => false,
|
||||
'date' => $date)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/wiki/feedfragment.xml');
|
||||
return $tmpl->render($context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Notification of change of a WikiPage.
|
||||
*
|
||||
* The content of a WikiPage is in the IDF_WikiRevision object,
|
||||
* this is why we send the notificatin from there. This means that
|
||||
* when the create flag is set, this is for the creation of a
|
||||
* wikipage and not, for the addition of a new revision.
|
||||
*
|
||||
* Usage:
|
||||
* <pre>
|
||||
* $this->notify($conf); // Notify the creation of a wiki page
|
||||
* $this->notify($conf, false); // Notify the update of the page
|
||||
* </pre>
|
||||
*
|
||||
* @param IDF_Conf Current configuration
|
||||
* @param bool Creation (true)
|
||||
*/
|
||||
public function notify($conf, $create=true)
|
||||
{
|
||||
if ('' == $conf->getVal('wiki_notification_email', '')) {
|
||||
return;
|
||||
}
|
||||
$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 %s - %s (%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 %s - %s (%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);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'),
|
||||
$conf->getVal('wiki_notification_email'),
|
||||
$title);
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
Pluf_Translation::loadSetLocale($current_locale);
|
||||
}
|
||||
}
|
||||
|
@@ -165,9 +165,17 @@ $cfg['db_database'] = 'website'; # put absolute path to the db if you
|
||||
# $cfg['idf_extra_upload_ext'] = ' ext1 ext2';
|
||||
#
|
||||
# By default, the size of the downloads is limited to 2MB.
|
||||
# The php.ini upload_max_filesize configuration setting will
|
||||
# always have precedence.
|
||||
# $cfg['max_upload_size'] = 2097152; // Size in bytes
|
||||
|
||||
# -- From this point you should not need to update anything. --
|
||||
#
|
||||
# Time zone
|
||||
# http://www.php.net/manual/en/timezones.php
|
||||
#
|
||||
# $cfg['time_zone'] = 'Europe/Berlin';
|
||||
|
||||
|
||||
$cfg['pear_path'] = '/usr/share/php';
|
||||
|
||||
$cfg['login_success_url'] = $cfg['url_base'].$cfg['idf_base'];
|
||||
|
38
src/IDF/conf/path.php-dist
Normal file
38
src/IDF/conf/path.php-dist
Normal file
@@ -0,0 +1,38 @@
|
||||
<?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 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 ***** */
|
||||
|
||||
/**
|
||||
* This file define the paths to where the Pluf and InDefero libraries
|
||||
* are installed. If you followed the recommended layout of the files
|
||||
* in the installation procedure, they should work out of the box.
|
||||
*
|
||||
* PLUF_PATH: path to the folder containing the Pluf.php file.
|
||||
* IDF_PATH: path to the folder containing the IDF folder.
|
||||
*/
|
||||
define('PLUF_PATH', dirname(__FILE__).'/../../../../pluf/src');
|
||||
define('IDF_PATH', dirname(__FILE__).'/../..');
|
||||
|
||||
set_include_path(get_include_path()
|
||||
.PATH_SEPARATOR.PLUF_PATH
|
||||
.PATH_SEPARATOR.IDF_PATH
|
||||
);
|
@@ -26,33 +26,28 @@ $base = Pluf::f('idf_base');
|
||||
|
||||
$ctl[] = array('regex' => '#^/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'index');
|
||||
|
||||
$ctl[] = array('regex' => '#^/login/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'login',
|
||||
'name' => 'login_view');
|
||||
|
||||
$ctl[] = array('regex' => '#^/preferences/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_User',
|
||||
'method' => 'myAccount');
|
||||
|
||||
$ctl[] = array('regex' => '#^/dashboard/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_User',
|
||||
'method' => 'dashboard',
|
||||
'name' => 'idf_dashboard');
|
||||
|
||||
$ctl[] = array('regex' => '#^/dashboard/submitted/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_User',
|
||||
'method' => 'dashboard',
|
||||
'params' => false,
|
||||
@@ -60,105 +55,88 @@ $ctl[] = array('regex' => '#^/dashboard/submitted/$#',
|
||||
|
||||
$ctl[] = array('regex' => '#^/u/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_User',
|
||||
'method' => 'view');
|
||||
|
||||
$ctl[] = array('regex' => '#^/logout/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'logout');
|
||||
|
||||
$ctl[] = array('regex' => '#^/help/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'faq');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'home');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/timeline/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'timeline');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/feed/timeline/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'timelineFeed',
|
||||
'name' => 'idf_project_timeline_feed');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/feed/timeline/token/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'timelineFeed',
|
||||
'name' => 'idf_project_timeline_feed_auth');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'index');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'search');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'view');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(\d+)/star/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'star');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/status/(\w+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'listStatus');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/label/(\d+)/(\w+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'listLabel');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/create/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'create');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/my/(\w+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'myIssues');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/attachment/(\d+)/(.*)$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'getAttachment');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/view/attachment/(\d+)/(.*)$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'viewAttachment');
|
||||
|
||||
@@ -166,61 +144,51 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/view/attachment/(\d+)/(.*)$#',
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/help/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'help');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/tree/([^/]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'treeBase');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/tree/([^/]+)/(.*)$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'tree');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/changes/([^/]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'changeLog');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/commit/([^/]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'commit');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/ddiff/([^/]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'downloadDiff');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/download/([^/]+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'download');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/file/([^/]+)/(.*)$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'getFile');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/treerev/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source_Svn',
|
||||
'method' => 'treeRev');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/source/changesrev/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source_Svn',
|
||||
'method' => 'changelogRev');
|
||||
|
||||
@@ -228,43 +196,41 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/source/changesrev/$#',
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'index');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/create/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'create');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/search/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'search');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/label/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'listLabel');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/update/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'update');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/delrev/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'deleteRev');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/delete/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'delete');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/page/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Wiki',
|
||||
'method' => 'view');
|
||||
|
||||
@@ -272,37 +238,31 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/page/(.*)/$#',
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Download',
|
||||
'method' => 'index');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/label/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Download',
|
||||
'method' => 'listLabel');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Download',
|
||||
'method' => 'view');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/(\d+)/get/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Download',
|
||||
'method' => 'download');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/create/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Download',
|
||||
'method' => 'submit');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/(\d+)/delete/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Download',
|
||||
'method' => 'delete');
|
||||
|
||||
@@ -310,25 +270,21 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/downloads/(\d+)/delete/$#',
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/review/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Review',
|
||||
'method' => 'index');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/review/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Review',
|
||||
'method' => 'view');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/review/create/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Review',
|
||||
'method' => 'create');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/review/getpatch/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Review',
|
||||
'method' => 'getPatch');
|
||||
|
||||
@@ -337,43 +293,36 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/review/getpatch/(\d+)/$#',
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'admin');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/issues/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminIssues');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/downloads/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminDownloads');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/wiki/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminWiki');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/source/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminSource');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/members/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminMembers');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/tabs/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminTabs');
|
||||
|
||||
@@ -381,19 +330,16 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/admin/tabs/$#',
|
||||
|
||||
$ctl[] = array('regex' => '#^/help/api/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'faqApi');
|
||||
|
||||
$ctl[] = array('regex' => '#^/api/p/([\-\w]+)/issues/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Api',
|
||||
'method' => 'issuesIndex');
|
||||
|
||||
$ctl[] = array('regex' => '#^/api/p/([\-\w]+)/issues/create/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Api',
|
||||
'method' => 'issueCreate');
|
||||
|
||||
@@ -401,43 +347,41 @@ $ctl[] = array('regex' => '#^/api/p/([\-\w]+)/issues/create/$#',
|
||||
|
||||
$ctl[] = array('regex' => '#^/admin/projects/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Admin',
|
||||
'method' => 'projects');
|
||||
|
||||
$ctl[] = array('regex' => '#^/admin/projects/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Admin',
|
||||
'method' => 'projectUpdate');
|
||||
|
||||
$ctl[] = array('regex' => '#^/admin/projects/create/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Admin',
|
||||
'method' => 'projectCreate');
|
||||
|
||||
$ctl[] = array('regex' => '#^/admin/projects/(\d+)/delete/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Admin',
|
||||
'method' => 'projectDelete');
|
||||
|
||||
$ctl[] = array('regex' => '#^/admin/users/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Admin',
|
||||
'method' => 'users');
|
||||
|
||||
$ctl[] = array('regex' => '#^/admin/users/create/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_Admin',
|
||||
'method' => 'userCreate');
|
||||
|
||||
$ctl[] = array('regex' => '#^/admin/users/notvalid/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Admin',
|
||||
'method' => 'usersNotValidated');
|
||||
|
||||
$ctl[] = array('regex' => '#^/admin/users/(\d+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Admin',
|
||||
'method' => 'userUpdate');
|
||||
|
||||
@@ -445,53 +389,48 @@ $ctl[] = array('regex' => '#^/admin/users/(\d+)/$#',
|
||||
|
||||
$ctl[] = array('regex' => '#^/register/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'register');
|
||||
|
||||
$ctl[] = array('regex' => '#^/register/k/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'registerConfirmation');
|
||||
|
||||
$ctl[] = array('regex' => '#^/register/ik/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'registerInputKey');
|
||||
|
||||
$ctl[] = array('regex' => '#^/password/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'passwordRecoveryAsk');
|
||||
|
||||
$ctl[] = array('regex' => '#^/password/ik/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'passwordRecoveryInputCode');
|
||||
|
||||
$ctl[] = array('regex' => '#^/password/k/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'passwordRecovery');
|
||||
|
||||
$ctl[] = array('regex' => '#^/preferences/email/ik/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_User',
|
||||
'method' => 'changeEmailInputKey');
|
||||
|
||||
$ctl[] = array('regex' => '#^/preferences/email/ak/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_User',
|
||||
'method' => 'changeEmailDo');
|
||||
|
||||
|
||||
$ctl[] = array('regex' => '#^/preferences/key/(\d+)/delete/$#',
|
||||
'base' => $base,
|
||||
'model' => 'IDF_Views_User',
|
||||
'method' => 'deleteKey');
|
||||
|
||||
|
||||
return $ctl;
|
||||
|
3514
src/IDF/locale/de/idf.po
Normal file
3514
src/IDF/locale/de/idf.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3500
src/IDF/locale/ru/idf.po
Normal file
3500
src/IDF/locale/ru/idf.po
Normal file
File diff suppressed because it is too large
Load Diff
3495
src/IDF/locale/sl/idf.po
Normal file
3495
src/IDF/locale/sl/idf.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -36,7 +36,8 @@ $m['IDF_WikiRevision'] = array('relate_to' => array('IDF_WikiPage', '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'));
|
||||
$m['IDF_Review_FileComment'] = array('relate_to' => array('IDF_Review_Patch', 'Pluf_User'));
|
||||
$m['IDF_Review_Comment'] = array('relate_to' => array('IDF_Review_Patch', 'Pluf_User'));
|
||||
$m['IDF_Review_FileComment'] = array('relate_to' => array('IDF_Review_Comment', 'Pluf_User'));
|
||||
$m['IDF_Key'] = array('relate_to' => array('Pluf_User'));
|
||||
$m['IDF_Conf'] = array('relate_to' => array('IDF_Project'));
|
||||
$m['IDF_Commit'] = array('relate_to' => array('IDF_Project', 'Pluf_User'));
|
||||
@@ -54,6 +55,10 @@ Pluf_Signal::connect('IDF_Project::created',
|
||||
array('IDF_Plugin_SyncSvn', 'entry'));
|
||||
Pluf_Signal::connect('Pluf_User::passwordUpdated',
|
||||
array('IDF_Plugin_SyncSvn', 'entry'));
|
||||
Pluf_Signal::connect('IDF_Project::preDelete',
|
||||
array('IDF_Plugin_SyncSvn', 'entry'));
|
||||
Pluf_Signal::connect('svnpostcommit.php::run',
|
||||
array('IDF_Plugin_SyncSvn', 'entry'));
|
||||
|
||||
#
|
||||
# Mercurial synchronization
|
||||
@@ -63,6 +68,8 @@ Pluf_Signal::connect('IDF_Project::created',
|
||||
array('IDF_Plugin_SyncMercurial', 'entry'));
|
||||
Pluf_Signal::connect('Pluf_User::passwordUpdated',
|
||||
array('IDF_Plugin_SyncMercurial', 'entry'));
|
||||
Pluf_Signal::connect('hgchangegroup.php::run',
|
||||
array('IDF_Plugin_SyncMercurial', 'entry'));
|
||||
|
||||
#
|
||||
# Git synchronization
|
||||
@@ -72,5 +79,10 @@ Pluf_Signal::connect('IDF_Key::postSave',
|
||||
array('IDF_Plugin_SyncGit', 'entry'));
|
||||
Pluf_Signal::connect('IDF_Project::created',
|
||||
array('IDF_Plugin_SyncGit', 'entry'));
|
||||
Pluf_Signal::connect('IDF_Key::preDelete',
|
||||
array('IDF_Plugin_SyncGit', 'entry'));
|
||||
Pluf_Signal::connect('gitpostupdate.php::run',
|
||||
array('IDF_Plugin_SyncGit', 'entry'));
|
||||
|
||||
|
||||
return $m;
|
||||
|
@@ -20,7 +20,12 @@
|
||||
<th>{trans 'Repository access:'}</th>
|
||||
<td>{$repository_access}
|
||||
</td>
|
||||
</tr>{if $remote_svn}
|
||||
</tr>{if $repository_size != -1}
|
||||
<tr>
|
||||
<th>{trans 'Repository size:'}</th>
|
||||
<td>{$repository_size|size}
|
||||
</td>
|
||||
</tr>{/if}{if $remote_svn}
|
||||
<tr>
|
||||
<th>{$form.f.svn_username.labelTag}:</th>
|
||||
<td>{if $form.f.svn_username.errors}{$form.f.svn_username.fieldErrors}{/if}
|
||||
|
@@ -53,6 +53,15 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td colspan="2" class="helptext">
|
||||
{blocktrans}
|
||||
Only project members and admins have write access to the source.<br />
|
||||
If you restrict the access to the source, anonymous access is<br />
|
||||
not provided and the users must authenticate themselves with their<br />
|
||||
password or SSH key.{/blocktrans}
|
||||
</td></tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.review_access_rights.labelTag}:</strong></th>
|
||||
<td>{if $form.f.review_access_rights.errors}{$form.f.review_access_rights.fieldErrors}{/if}
|
||||
{$form.f.review_access_rights|unsafe}
|
||||
|
@@ -49,7 +49,7 @@
|
||||
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
||||
{if $hasReviewAccess} <a href="{url 'IDF_Views_Review::index', array($project.shortname)}"{block tabreview}{/block}>{trans 'Code Review'}</a>{/if}
|
||||
{if $isOwner}
|
||||
<a href="{url 'IDF_Views_Project::admin', array($project.shortname)}"{block tabadmin}{/block}>{trans 'Administer'}</a>{/if}{/if}
|
||||
<a href="{url 'IDF_Views_Project::admin', array($project.shortname)}"{block tabadmin}{/block}>{trans 'Project Management'}</a>{/if}{/if}
|
||||
</div>
|
||||
{block subtabs}{if $user.isAnonymous()} | {aurl 'url', 'IDF_Views::login'}{blocktrans}<a href="{$url}">Sign in or create your account</a> to create issues or add comments{/blocktrans}{/if}{/block}
|
||||
</div>
|
||||
@@ -73,15 +73,18 @@
|
||||
{include 'idf/js-hotkeys.html'}
|
||||
{block javascript}{/block}
|
||||
{if $project}
|
||||
<script type="text/javascript">{literal}
|
||||
<!-- //
|
||||
$(document).ready(function(){
|
||||
<script type="text/javascript" charset="utf-8">{literal}
|
||||
//<![CDATA[
|
||||
$(document).ready(function(){
|
||||
var frag = location.hash;
|
||||
if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
||||
if ($('#preview').length) {
|
||||
location.hash = '#preview';
|
||||
}
|
||||
else if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
||||
$(frag).addClass("issue-comment-focus");
|
||||
}
|
||||
});
|
||||
// -->{/literal}
|
||||
//]]>{/literal}
|
||||
</script>{/if}
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -35,7 +35,7 @@
|
||||
<div id="hd">
|
||||
<p class="top"><a href="#title" accesskey="2"></a>
|
||||
{if !$user.isAnonymous()}{aurl 'url', 'idf_dashboard'}{blocktrans}Welcome, <strong><a class="userw" href="{$url}">{$user}</a></strong>.{/blocktrans} <a href="{url 'IDF_Views::logout'}">{trans 'Sign Out'}</a>{else}<a href="{url 'IDF_Views::login'}">{trans 'Sign in or create your account'}</a>{/if}
|
||||
| <a href="{url 'IDF_Views::index'}">{trans 'Project List'}</a> {if $isAdmin}| <a href="{url 'IDF_Views_Admin::projects'}">{trans 'Administer'}</a>{/if}
|
||||
| <a href="{url 'IDF_Views::index'}">{trans 'Project List'}</a> {if $isAdmin}| <a href="{url 'IDF_Views_Admin::projects'}">{trans 'Forge Management'}</a>{/if}
|
||||
| <a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a>
|
||||
</p>
|
||||
<h1 id="title" class="title">{block title}{$page_title}{/block}</h1>
|
||||
|
@@ -37,7 +37,7 @@
|
||||
<p class="top"><a href="#title" accesskey="2"></a>
|
||||
{if !$user.isAnonymous()}{aurl 'url', 'idf_dashboard'}{blocktrans}Welcome, <strong><a class="userw" href="{$url}">{$user}</a></strong>.{/blocktrans} <a href="{url 'IDF_Views::logout'}">{trans 'Sign Out'}</a>{else}<a href="{url 'IDF_Views::login'}">{trans 'Sign in or create your account'}</a>{/if}
|
||||
{if $project} | <a href="{url 'IDF_Views::index'}">{trans 'Project List'}</a>{/if}
|
||||
{if $isAdmin}| <a href="{url 'IDF_Views_Admin::projects'}">{trans 'Administer'}</a>{/if}
|
||||
{if $isAdmin}| <a href="{url 'IDF_Views_Admin::projects'}">{trans 'Forge Management'}</a>{/if}
|
||||
| <a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a>
|
||||
</p>
|
||||
<div id="header">
|
||||
@@ -50,7 +50,7 @@
|
||||
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
||||
{if $hasReviewAccess} <a href="{url 'IDF_Views_Review::index', array($project.shortname)}"{block tabreview}{/block}>{trans 'Code Review'}</a>{/if}
|
||||
{if $isOwner}
|
||||
<a href="{url 'IDF_Views_Project::admin', array($project.shortname)}"{block tabadmin}{/block}>{trans 'Administer'}</a>{/if}{/if}
|
||||
<a href="{url 'IDF_Views_Project::admin', array($project.shortname)}"{block tabadmin}{/block}>{trans 'Project Management'}</a>{/if}{/if}
|
||||
</div>
|
||||
{block subtabs}{if $user.isAnonymous()} | {aurl 'url', 'IDF_Views::login'}{blocktrans}<a href="{$url}">Sign in or create your account</a> to create issues or add comments{/blocktrans}{/if}{/block}
|
||||
</div>
|
||||
@@ -75,15 +75,18 @@
|
||||
{include 'idf/js-hotkeys.html'}
|
||||
{block javascript}{/block}
|
||||
{if $project}
|
||||
<script type="text/javascript">{literal}
|
||||
<!-- //
|
||||
$(document).ready(function(){
|
||||
<script type="text/javascript" charset="utf-8">{literal}
|
||||
//<![CDATA[
|
||||
$(document).ready(function(){
|
||||
var frag = location.hash;
|
||||
if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
||||
if ($('#preview').length) {
|
||||
location.hash = '#preview';
|
||||
}
|
||||
else if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
||||
$(frag).addClass("issue-comment-focus");
|
||||
}
|
||||
});
|
||||
// -->{/literal}
|
||||
//]]>{/literal}
|
||||
</script>{/if}
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -10,3 +10,8 @@
|
||||
{foreach $tags as $tag} {$tag.class|safe}:{$tag.name|safe}
|
||||
{/foreach}{/if}
|
||||
{trans 'Download:'} {$urlfile}
|
||||
{if $file.changelog}
|
||||
{trans 'Description:'}
|
||||
|
||||
{$file.changelog}
|
||||
{/if}
|
||||
|
14
src/IDF/templates/idf/downloads/feedfragment.xml
Normal file
14
src/IDF/templates/idf/downloads/feedfragment.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<entry>
|
||||
<title>{$title}</title>
|
||||
<link href="{$url}"/>
|
||||
<id>{$url}</id>
|
||||
<updated>{$date}</updated>
|
||||
<author>{$file.get_submitter()}</author>
|
||||
<content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p>{$file} - {$file.filesize|ssize}</p>
|
||||
{if $file.changelog}
|
||||
<h2>{trans 'Details'}</h2>
|
||||
{markdown $file.changelog, $request}
|
||||
{/if}
|
||||
</div></content>
|
||||
</entry>
|
@@ -19,6 +19,12 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$form.f.changelog.labelTag}:</th>
|
||||
<td>{if $form.f.changelog.errors}{$form.f.changelog.fieldErrors}{/if}
|
||||
{$form.f.changelog|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.file.labelTag}:</strong></th>
|
||||
<td>{if $form.f.file.errors}{$form.f.file.fieldErrors}{/if}
|
||||
{$form.f.file|unsafe}
|
||||
@@ -50,6 +56,8 @@
|
||||
<p>{blocktrans}Each file must have a distinct name and file contents
|
||||
cannot be changed, so be sure to include release numbers in each file
|
||||
name.{/blocktrans}</p>
|
||||
{assign $url = 'http://daringfireball.net/projects/markdown/syntax'}
|
||||
<p>{blocktrans}You can use the <a href="{$url}">Markdown syntax</a> for the description.{/blocktrans}</p>
|
||||
</div>
|
||||
{/block}
|
||||
{block javascript}
|
||||
|
@@ -6,7 +6,11 @@
|
||||
{if $deprecated}<p class="smaller">{blocktrans}<strong>Attention!</strong> This file is marked as deprecated, download it only if you are sure you need this specific version.{/blocktrans}</p>{/if}
|
||||
<a href="{url 'IDF_Views_Download::download', array($project.shortname, $file.id)}">{$file}</a> - {$file.filesize|size}
|
||||
</div>
|
||||
{if $file.changelog}
|
||||
<h2 class="changes">{trans 'Changes'}</h2>
|
||||
|
||||
{markdown $file.changelog, $request}
|
||||
{/if}
|
||||
|
||||
{if $form}
|
||||
{if $form.errors}
|
||||
@@ -19,7 +23,7 @@
|
||||
{/if}
|
||||
|
||||
<form method="post" enctype="multipart/form-data" action=".">
|
||||
<table class="form" summary="">
|
||||
<table class="form download" summary="">
|
||||
<tr>
|
||||
<th><strong>{$form.f.summary.labelTag}:</strong></th>
|
||||
<td>{if $form.f.summary.errors}{$form.f.summary.fieldErrors}{/if}
|
||||
@@ -27,6 +31,12 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$form.f.changelog.labelTag}:</th>
|
||||
<td>{if $form.f.changelog.errors}{$form.f.changelog.fieldErrors}{/if}
|
||||
{$form.f.changelog|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$form.f.label1.labelTag}:</th>
|
||||
<td>
|
||||
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
|
||||
@@ -39,7 +49,8 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>{aurl 'url', 'IDF_Views_Download::delete', array($project.shortname, $file.id)}
|
||||
<td><input type="submit" value="{trans 'Update File'}" name="submit" /> | <a href="{url 'IDF_Views_Download::index', array($project.shortname)}">{trans 'Cancel'}</a> <span class="dellink"><a href="{$url}" title="{trans 'Remove this file'}"><img src="{media '/idf/img/trash.png'}" style="vertical-align: text-bottom;" alt="{trans 'Trash'}" /></a> <a href="{$url}" title="{trans 'Remove this file'}">{trans 'Delete this file'}</a></span>
|
||||
<td>{* float left is a fix for Firefox < 3.5 *}
|
||||
<span style="float: left;"><input type="submit" value="{trans 'Update File'}" name="submit" /> | <a href="{url 'IDF_Views_Download::index', array($project.shortname)}">{trans 'Cancel'}</a></span> <span class="dellink"><a href="{$url}" title="{trans 'Remove this file'}"><img src="{media '/idf/img/trash.png'}" style="vertical-align: text-bottom;" alt="{trans 'Trash'}" /></a> <a href="{$url}" title="{trans 'Remove this file'}">{trans 'Delete this file'}</a></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@@ -36,6 +36,7 @@
|
||||
<p class="top"><a href="#title" accesskey="2"></a>
|
||||
{aurl 'url', 'IDF_Views_User::dashboard'}{blocktrans}Welcome, <strong><a class="userw" href="{$url}">{$user}</a></strong>.{/blocktrans} <a href="{url 'IDF_Views::logout'}">{trans 'Sign Out'}</a>
|
||||
| <a href="{url 'IDF_Views::index'}">{trans 'Project List'}</a>
|
||||
| <a href="{url 'IDF_Views_Admin::projects'}">{trans 'Forge Management'}</a>
|
||||
| <a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a>
|
||||
</p>
|
||||
<div id="header">
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user