Compare commits
78 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2d271f6b69 | ||
|
57a5b4738a | ||
|
fad12e17c7 | ||
|
2c7b3e1e1a | ||
|
ccc41c86b0 | ||
|
763d7ca7f6 | ||
|
e4902ef76e | ||
|
02e00054f6 | ||
|
0ee7dc5a89 | ||
|
5b411228c2 | ||
|
0e3a74558c | ||
|
109431cd40 | ||
|
a8db15d1e5 | ||
|
0d4a31c086 | ||
|
2a1628f8de | ||
|
2e36487be4 | ||
|
643650a6a7 | ||
|
a1e10bd169 | ||
|
5275a1a9d6 | ||
|
0918d1d542 | ||
|
7955aa6077 | ||
|
0ea5171f3e | ||
|
4175fe030b | ||
|
1a030ea4ed | ||
|
b2356bd157 | ||
|
32fb0cb121 | ||
|
740979a4cb | ||
|
1cf3a73fe1 | ||
|
88d39faed7 | ||
|
685d3974e8 | ||
|
59a81279ff | ||
|
bd0209a28e | ||
|
6360ea93be | ||
|
4b2139fe99 | ||
|
fcc1283001 | ||
|
7383e18dff | ||
|
1831716b07 | ||
|
553f5179a2 | ||
|
19ca5ef02f | ||
|
a8699db268 | ||
|
3b5251c1b4 | ||
|
7070e8a13a | ||
|
bac1586334 | ||
|
1cb8e44ff9 | ||
|
78cf0c1c85 | ||
|
9f67343e36 | ||
|
64f41c0cd2 | ||
|
884a41fbba | ||
|
330fa62554 | ||
|
3990098e4b | ||
|
5e3b2bac28 | ||
|
366b73d27e | ||
|
b4cac893a5 | ||
|
9dedea0f9d | ||
|
0a868a76ba | ||
|
31c79419b5 | ||
|
6ad7ee8c71 | ||
|
da1ddc4179 | ||
|
e1f961c14b | ||
|
f40d197478 | ||
|
7a5bb7345d | ||
|
fb9d52fa87 | ||
|
e6df530624 | ||
|
54d3783173 | ||
|
9e2d9e691b | ||
|
bf8a33708b | ||
|
a105f971c2 | ||
|
4119a160aa | ||
|
495e18cf58 | ||
|
49f339c7c5 | ||
|
d46ddea543 | ||
|
cf9360a1a8 | ||
|
953d7c4ecd | ||
|
f4f8f9615a | ||
|
4c5bd8d2be | ||
|
fd6031d7f5 | ||
|
83658ac860 | ||
|
593afd9b8b |
3
.gitignore
vendored
@@ -2,3 +2,6 @@ tmp
|
||||
src/IDF/conf/idf.php
|
||||
src/IDF/conf/idf.test.php
|
||||
www/test.php
|
||||
www/media/upload
|
||||
src/IDF/gettexttemplates
|
||||
indefero-*.zip
|
||||
|
280
COPYING
Normal file
@@ -0,0 +1,280 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
39
INSTALL.mdtext
Normal file
@@ -0,0 +1,39 @@
|
||||
# Quick installation instruction
|
||||
|
||||
* Checkout the trunk of [Pluf](http://www.pluf.org).
|
||||
* 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.
|
||||
* Run `php /path/to/pluf/src/migrate.php --conf=IDF/conf/idf.php -a -i -d -u` to test the installation of the tables.
|
||||
* Run `php /path/to/pluf/src/migrate.php --conf=IDF/conf/idf.php -a -i -d` to really install the tables.
|
||||
* Create a bootsrap file to create the first project and admin user for example `www/bootstrap.php`:
|
||||
|
||||
<?php
|
||||
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).'/../src');
|
||||
set_include_path(get_include_path().PATH_SEPARATOR.'/path/to/pluf/src');
|
||||
require 'Pluf.php';
|
||||
Pluf::start(dirname(__FILE__).'/IDF/conf/idf.php');
|
||||
Pluf_Dispatcher::loadControllers(Pluf::f('idf_views'));
|
||||
|
||||
$project = new IDF_Project();
|
||||
$project->name = 'Your project';
|
||||
$project->shortname = 'yourproject'; //Only letters digits
|
||||
$project->description = 'This is your project.';
|
||||
$project->create();
|
||||
$user = new Pluf_User();
|
||||
$user->first_name = 'John';
|
||||
$user->last_name = 'Doe';
|
||||
$user->login = 'doe';
|
||||
$user->email = 'doe@example.com';
|
||||
$user->password = 'yourpassword'; // the password is salted/hashed
|
||||
// in the database, so do not worry :)
|
||||
$user->administrator = true;
|
||||
$user->active = true;
|
||||
$user->create();
|
||||
print "Bootstrap ok\n";
|
||||
?>
|
||||
|
||||
* Run `php bootstrap.php`.
|
||||
* Remove the `bootstrp.php` file.
|
||||
|
||||
Now you can login with this user into the interface.
|
||||
|
109
logo/indefero-logo.svg
Normal file
@@ -0,0 +1,109 @@
|
||||
<?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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1052.3622"
|
||||
height="744.09448"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
version="1.0"
|
||||
sodipodi:docname="indefero-logo.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs4">
|
||||
<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" />
|
||||
</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="1"
|
||||
inkscape:cx="538.31563"
|
||||
inkscape:cy="375.31517"
|
||||
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">
|
||||
<g
|
||||
id="g2401"
|
||||
transform="matrix(1.21,0,0,1.21,-216.85419,33.719307)"
|
||||
style="fill:#8ae234;stroke:#4e9a06;stroke-width:2.4000001;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero/logo/powered-by-indefero.png"
|
||||
inkscape:export-xdpi="12.330909"
|
||||
inkscape:export-ydpi="12.330909">
|
||||
<path
|
||||
id="path2383"
|
||||
d="M 396.19089,173.14471 C 388.51468,173.95132 381.78894,178.53877 376.60988,184.03602 C 369.37391,191.91606 364.91246,202.1151 363.2879,212.63964 C 361.5643,223.92137 363.02865,235.84599 368.36476,246.01235 C 372.15083,253.25619 377.89637,259.93574 385.66177,262.98007 C 389.52655,264.51944 394.64539,264.01291 397.34089,260.56971 C 399.98446,257.00261 400.03552,252.33571 400.19845,248.08104 C 400.24345,240.4705 399.65096,232.8256 400.65463,225.24911 C 401.52594,215.74288 404.69407,206.6816 407.37075,197.5806 C 408.53317,193.13727 409.62169,188.55252 409.34574,183.93072 C 408.85757,179.30596 405.76515,174.6203 401.04934,173.52402 C 399.47445,173.0752 397.81522,173.03454 396.19089,173.14471 z"
|
||||
style="fill:#8ae234;fill-opacity:1;fill-rule:nonzero;stroke:#4e9a06;stroke-width:2.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
id="path2391"
|
||||
d="M 433.14691,149.28687 C 440.35281,152.05276 445.66203,158.22465 449.24185,164.87502 C 454.19176,174.35936 455.86147,185.3656 454.70671,195.95197 C 453.45166,207.29539 448.95089,218.43468 441.16537,226.87356 C 435.63345,232.89065 428.35489,237.85554 420.06619,238.78632 C 415.93465,239.27292 411.12133,237.45884 409.40885,233.43528 C 407.77858,229.30552 408.93715,224.78444 409.88097,220.63259 C 411.80725,213.26972 414.35818,206.03866 415.34967,198.46058 C 416.96842,189.05274 416.25348,179.48024 416.02353,169.99656 C 416.05073,165.40378 416.18593,160.69353 417.64868,156.30064 C 419.31719,151.95982 423.51697,148.23419 428.35584,148.3958 C 429.99322,148.36988 431.60645,148.76004 433.14691,149.28687 z"
|
||||
style="fill:#8ae234;fill-opacity:1;fill-rule:nonzero;stroke:#4e9a06;stroke-width:2.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:144px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;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="337"
|
||||
y="355.09448"
|
||||
id="text2397"
|
||||
sodipodi:linespacing="100%"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero/logo/powered-by-indefero.png"
|
||||
inkscape:export-xdpi="12.330909"
|
||||
inkscape:export-ydpi="12.330909"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2399"
|
||||
x="337"
|
||||
y="355.09448">InDefero</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:semi-condensed;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans Semi-Condensed"
|
||||
x="346"
|
||||
y="241.09448"
|
||||
id="text3195"
|
||||
sodipodi:linespacing="125%"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero/logo/powered-by-indefero.png"
|
||||
inkscape:export-xdpi="12.330909"
|
||||
inkscape:export-ydpi="12.330909"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3197"
|
||||
x="346"
|
||||
y="241.09448">Powered by</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.7 KiB |
BIN
logo/powered-by-indefero.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
172
logo/star.svg
Normal file
@@ -0,0 +1,172 @@
|
||||
<?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"
|
||||
version="1.0"
|
||||
width="96"
|
||||
height="48"
|
||||
id="svg0"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docname="star.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<metadata
|
||||
id="metadata2536">
|
||||
<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>
|
||||
<sodipodi:namedview
|
||||
inkscape:cy="15"
|
||||
inkscape:cx="49.903061"
|
||||
inkscape:zoom="4"
|
||||
inkscape:window-height="755"
|
||||
inkscape:window-width="969"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base"
|
||||
showgrid="false"
|
||||
inkscape:window-x="220"
|
||||
inkscape:window-y="108"
|
||||
inkscape:current-layer="svg0" />
|
||||
<defs
|
||||
id="defs">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 24 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="48 : 24 : 1"
|
||||
inkscape:persp3d-origin="24 : 16 : 1"
|
||||
id="perspective2538" />
|
||||
<linearGradient
|
||||
id="G0">
|
||||
<stop
|
||||
id="s1"
|
||||
style="stop-color:#e6cf00;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="s2"
|
||||
style="stop-color:#fde94a;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="G1">
|
||||
<stop
|
||||
id="s3"
|
||||
style="stop-color:#fcf9fb;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="s4"
|
||||
style="stop-color:#fcf9fb;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="G2">
|
||||
<stop
|
||||
id="s5"
|
||||
style="stop-color:#000000;stop-opacity:0.63"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="s6"
|
||||
style="stop-color:#000000;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="14.660452"
|
||||
y1="7.0243196"
|
||||
x2="24.030643"
|
||||
y2="34.826122"
|
||||
id="G3"
|
||||
xlink:href="#G1"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
cx="24"
|
||||
cy="22"
|
||||
r="22"
|
||||
fx="24"
|
||||
fy="22"
|
||||
id="R0"
|
||||
xlink:href="#G0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,-0.2,0.2,1,-3.8,6.8)" />
|
||||
<radialGradient
|
||||
cx="17.3125"
|
||||
cy="25.53125"
|
||||
r="9.6875"
|
||||
fx="17.3125"
|
||||
fy="25.53125"
|
||||
id="R1"
|
||||
xlink:href="#G2"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.4,0,0,0.67,-17.1,22.4)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#G1"
|
||||
id="linearGradient2548"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="14.660452"
|
||||
y1="7.0243196"
|
||||
x2="24.030643"
|
||||
y2="34.826122"
|
||||
gradientTransform="translate(47.948863,0.5)" />
|
||||
</defs>
|
||||
<path
|
||||
d="M 37.310531,41.5 L 24.030644,34.826121 L 10.735101,41.471448 L 13.289408,27.369086 L 2.5511635,17.368344 L 17.409702,15.326301 L 24.068641,2.5 L 30.697416,15.340488 L 45.551111,17.414249 L 34.789382,27.392039 L 37.310531,41.5 z"
|
||||
id="star"
|
||||
style="fill:url(#R0);stroke:#c4a000"
|
||||
inkscape:export-xdpi="36"
|
||||
inkscape:export-ydpi="36" />
|
||||
<path
|
||||
d="M 17.731857,15.79089 L 24.06374,3.5868195 L 30.369452,15.794804 L 44.440148,17.761498 L 40.820395,21.121507 C 24.382895,17.434007 31.36502,28.341981 13.251748,30.364721 L 13.819799,27.184324 L 3.6604518,17.718688 C 3.6604518,17.718688 17.731857,15.79089 17.731857,15.79089 z"
|
||||
id="hl"
|
||||
style="opacity:0.8;fill:url(#G3);stroke:none"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero/www/media/idf/img/star.png"
|
||||
inkscape:export-xdpi="36"
|
||||
inkscape:export-ydpi="36" />
|
||||
<path
|
||||
d="M 35.973752,39.712833 L 24.028333,33.709386 L 12.082531,39.678326 L 14.362768,27.008543 L 4.7776396,18.070249 L 18.056076,16.247921 L 24.062792,4.6783526 L 30.045232,16.255741 L 43.322959,18.11306 L 33.713703,27.034785 L 35.973752,39.712833 z"
|
||||
id="ol"
|
||||
style="opacity:0.68999999;fill:none;stroke:#ffffff"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero/www/media/idf/img/star.png"
|
||||
inkscape:export-xdpi="36"
|
||||
inkscape:export-ydpi="36" />
|
||||
<path
|
||||
d="M 85.259394,42 L 71.979507,35.326121 L 58.683964,41.971448 L 61.238271,27.869086 L 50.500026,17.868344 L 65.358565,15.826301 L 72.017504,3 L 78.646279,15.840488 L 93.499974,17.914249 L 82.738245,27.892039 L 85.259394,42 z"
|
||||
id="path2540"
|
||||
style="fill:#d3d7cf;stroke:#babdb6"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero/www/media/idf/img/star-grey.png"
|
||||
inkscape:export-xdpi="36"
|
||||
inkscape:export-ydpi="36" />
|
||||
<path
|
||||
d="M 65.68072,16.29089 L 72.012603,4.08682 L 78.318315,16.294804 L 92.389011,18.261498 L 88.769258,21.621507 C 72.331758,17.934007 79.313883,28.841981 61.200611,30.864721 L 61.768662,27.684324 L 51.609315,18.218688 C 51.609315,18.218688 65.68072,16.29089 65.68072,16.29089 z"
|
||||
id="path2542"
|
||||
style="opacity:0.8;fill:url(#linearGradient2548);stroke:none"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero/www/media/idf/img/star-grey.png"
|
||||
inkscape:export-xdpi="36"
|
||||
inkscape:export-ydpi="36" />
|
||||
<path
|
||||
d="M 83.922615,40.212833 L 71.977196,34.209386 L 60.031394,40.178326 L 62.311631,27.508543 L 52.726502,18.570249 L 66.004939,16.747921 L 72.011655,5.178353 L 77.994095,16.755741 L 91.271822,18.61306 L 81.662566,27.534785 L 83.922615,40.212833 z"
|
||||
id="path2544"
|
||||
style="opacity:0.68999999;fill:none;stroke:#ffffff"
|
||||
inkscape:export-filename="/home/loa/Projects/indefero/www/media/idf/img/star-grey.png"
|
||||
inkscape:export-xdpi="36"
|
||||
inkscape:export-ydpi="36" />
|
||||
</svg>
|
After Width: | Height: | Size: 6.3 KiB |
10
release-script
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
last="$1"
|
||||
new="$2"
|
||||
echo "xgettext -o idf.pot -p ./IDF/locale --force-po --from-code=UTF-8 --keyword --keyword=__ --keyword=_n:1,2 -L PHP ./IDF/*.php"
|
||||
echo "find ./ -iname \"*.php\" -exec xgettext -o idf.pot -p ./IDF/locale/ --from-code=UTF-8 -j --keyword --keyword=__ --keyword=_n:1,2 -L PHP {} \;"
|
||||
echo "# git tag v$new"
|
||||
echo "git archive --format=zip --prefix=indefero-$new/ v$new > indefero-$new.zip"
|
||||
echo "git log --no-merges v$new ^v$last > ChangeLog-$new"
|
||||
echo "git shortlog --no-merges v$new ^v$last > ShortLog"
|
||||
echo "git diff --stat --summary -M v$last v$new > diffstat-$new"
|
@@ -86,7 +86,7 @@ class IDF_Conf extends Pluf_Model
|
||||
function initCache()
|
||||
{
|
||||
$this->datacache = new ArrayObject();
|
||||
$sql = new Pluf_SQL('project=%s', $this->_project);
|
||||
$sql = new Pluf_SQL('project=%s', $this->_project->id);
|
||||
foreach ($this->getList(array('filter' => $sql->gen())) as $val) {
|
||||
$this->datacache[$val->vkey] = $val->vdesc;
|
||||
}
|
||||
@@ -122,7 +122,7 @@ class IDF_Conf extends Pluf_Model
|
||||
function delVal($key, $initcache=true)
|
||||
{
|
||||
$gconf = new IDF_Conf();
|
||||
$sql = new Pluf_SQL('vkey=%s AND project=%s', array($key, $this->_project));
|
||||
$sql = new Pluf_SQL('vkey=%s AND project=%s', array($key, $this->_project->id));
|
||||
foreach ($gconf->getList(array('filter' => $sql->gen())) as $c) {
|
||||
$c->delete();
|
||||
}
|
||||
|
@@ -46,6 +46,7 @@ class IDF_Diff
|
||||
$current_chunk = 0;
|
||||
$lline = 0;
|
||||
$rline = 0;
|
||||
$files = array();
|
||||
foreach ($this->lines as $line) {
|
||||
if (0 === strpos($line, 'diff --git a')) {
|
||||
$current_file = self::getFile($line);
|
||||
@@ -55,6 +56,14 @@ class IDF_Diff
|
||||
$current_chunk = 0;
|
||||
continue;
|
||||
}
|
||||
if (0 === strpos($line, 'Index: ')) {
|
||||
$current_file = self::getSvnFile($line);
|
||||
$files[$current_file] = array();
|
||||
$files[$current_file]['chunks'] = array();
|
||||
$files[$current_file]['chunks_def'] = array();
|
||||
$current_chunk = 0;
|
||||
continue;
|
||||
}
|
||||
if (0 === strpos($line, '@@ ')) {
|
||||
$files[$current_file]['chunks_def'][] = self::getChunk($line);
|
||||
$files[$current_file]['chunks'][] = array();
|
||||
@@ -94,6 +103,11 @@ class IDF_Diff
|
||||
return trim(substr($line, 3, $n-3));
|
||||
}
|
||||
|
||||
public static function getSvnFile($line)
|
||||
{
|
||||
return substr(trim($line), 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the html version of a parsed diff.
|
||||
*/
|
||||
|
@@ -220,9 +220,6 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
||||
foreach ($tags as $tag) {
|
||||
$issue->setAssoc($tag);
|
||||
}
|
||||
$issue->setAssoc($this->user); // the user is
|
||||
// automatically
|
||||
// interested.
|
||||
// add the first comment
|
||||
$comment = new IDF_IssueComment();
|
||||
$comment->issue = $issue;
|
||||
|
@@ -253,6 +253,10 @@ class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
||||
$comment->changes = $changes;
|
||||
$comment->create();
|
||||
$this->issue->update();
|
||||
if ($this->issue->owner != $this->user->id and
|
||||
$this->issue->submitter != $this->user->id) {
|
||||
$this->issue->setAssoc($this->user); // interested user.
|
||||
}
|
||||
return $this->issue;
|
||||
}
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
|
@@ -36,12 +36,12 @@ class IDF_Form_Register extends Pluf_Form
|
||||
$this->fields['login'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your login'),
|
||||
'max_length' => 8,
|
||||
'max_length' => 15,
|
||||
'min_length' => 3,
|
||||
'initial' => $login,
|
||||
'help_text' => __('The login must be between 3 and 8 characters long and contains only letters and digits.'),
|
||||
'help_text' => __('The login must be between 3 and 15 characters long and contains only letters and digits.'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 8,
|
||||
'maxlength' => 15,
|
||||
'size' => 10,
|
||||
),
|
||||
));
|
||||
|
57
src/IDF/Form/TabsConf.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?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 ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the tabs access.
|
||||
*/
|
||||
class IDF_Form_TabsConf extends Pluf_Form
|
||||
{
|
||||
public $conf = null;
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->conf = $extra['conf'];
|
||||
$ak = array('downloads_access_rights' => __('Downloads'),
|
||||
'source_access_rights' => __('Source'),
|
||||
'issues_access_rights' => __('Issues'),);
|
||||
foreach ($ak as $key=>$label) {
|
||||
$this->fields[$key] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => $label,
|
||||
'initial' => $this->conf->getVal($key, 'all'),
|
||||
'widget_attrs' => array('choices' =>
|
||||
array(
|
||||
__('Open to all') => 'all',
|
||||
__('Signed in users') => 'login',
|
||||
__('Project members') => 'members',
|
||||
__('Project owners') => 'owners',
|
||||
__('Closed') => 'none',
|
||||
)
|
||||
),
|
||||
'widget' => 'Pluf_Form_Widget_SelectInput',
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
141
src/IDF/Form/UpdateUpload.php
Normal file
@@ -0,0 +1,141 @@
|
||||
<?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 ***** */
|
||||
|
||||
/**
|
||||
* Update a file for download.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_UpdateUpload extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $upload = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
$this->upload = $extra['upload'];
|
||||
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Summary'),
|
||||
'initial' => $this->upload->summary,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$tags = $this->upload->get_tags_list();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$initial = '';
|
||||
if (isset($tags[$i-1])) {
|
||||
if ($tags[$i-1]->class != 'Other') {
|
||||
$initial = (string) $tags[$i-1];
|
||||
} else {
|
||||
$initial = $tags[$i-1]->name;
|
||||
}
|
||||
}
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => $initial,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than label from the %s class to an issue.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// Add a tag for each label
|
||||
$tags = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tag = IDF_Tag::add($name, $this->project, $class);
|
||||
$tags[] = $tag->id;
|
||||
}
|
||||
}
|
||||
// Create the upload
|
||||
$this->upload->summary = trim($this->cleaned_data['summary']);
|
||||
$this->upload->modif_dtime = gmdate('Y-m-d H:i:s');
|
||||
$this->upload->update();
|
||||
$this->upload->batchAssoc('IDF_Tag', $tags);
|
||||
return $this->upload;
|
||||
}
|
||||
}
|
||||
|
153
src/IDF/Form/Upload.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?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 ***** */
|
||||
|
||||
/**
|
||||
* Upload a file for download.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_Upload extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Summary'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['file'] = new Pluf_Form_Field_File(
|
||||
array('required' => true,
|
||||
'label' => __('File'),
|
||||
'initial' => '',
|
||||
'move_function_params' => array('upload_path' => Pluf::f('upload_path').'/'.$this->project->shortname.'/files',
|
||||
'upload_path_create' => true,
|
||||
'upload_overwrite' => false),
|
||||
|
||||
));
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function clean_file()
|
||||
{
|
||||
if (!preg_match('/\.(png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|wmv|zip)$/i', $this->cleaned_data['file'])) {
|
||||
throw new Pluf_Form_Invalid(__('For security reason, you cannot upload a file with this extension.'));
|
||||
}
|
||||
return $this->cleaned_data['file'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (split(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than label from the %s class to an issue.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// Add a tag for each label
|
||||
$tags = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tags[] = IDF_Tag::add($name, $this->project, $class);
|
||||
}
|
||||
}
|
||||
// Create the upload
|
||||
$upload = new IDF_Upload();
|
||||
$upload->project = $this->project;
|
||||
$upload->submitter = $this->user;
|
||||
$upload->summary = trim($this->cleaned_data['summary']);
|
||||
$upload->file = $this->cleaned_data['file'];
|
||||
$upload->filesize = filesize(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']);
|
||||
$upload->downloads = 0;
|
||||
$upload->create();
|
||||
foreach ($tags as $tag) {
|
||||
$upload->setAssoc($tag);
|
||||
}
|
||||
return $upload;
|
||||
}
|
||||
}
|
||||
|
70
src/IDF/Form/UploadConf.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?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 ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the labels etc. for the uploaded files.
|
||||
*/
|
||||
class IDF_Form_UploadConf extends Pluf_Form
|
||||
{
|
||||
/**
|
||||
* Defined as constants to easily access the value in the
|
||||
* form in the case nothing is in the db yet.
|
||||
*/
|
||||
const init_predefined = 'Featured = Listed on project home page
|
||||
Type:Executable = Executable application
|
||||
Type:Installer = Download and run to install application
|
||||
Type:Package = Your OS package manager installs this
|
||||
Type:Archive = Download, unarchive, then follow directions
|
||||
Type:Source = Source code archive
|
||||
Type:Docs = This file contains documentation
|
||||
OpSys:All = Works with all operating systems
|
||||
OpSys:Windows = Works with Windows
|
||||
OpSys:Linux = Works with Linux
|
||||
OpSys:OSX = Works with Mac OS X
|
||||
Deprecated = Most users should NOT download this';
|
||||
|
||||
const init_one_max = 'Type';
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['labels_download_predefined'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Predefined download labels'),
|
||||
'initial' => self::init_predefined,
|
||||
'widget_attrs' => array('rows' => 13,
|
||||
'cols' => 75),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
|
||||
$this->fields['labels_download_one_max'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Each download may have at most one label with each of these classes'),
|
||||
'initial' => self::init_one_max,
|
||||
'widget_attrs' => array('size' => 60),
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
136
src/IDF/Form/UserAccount.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?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 a user to update its details.
|
||||
*/
|
||||
class IDF_Form_UserAccount extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->fields['first_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('First name'),
|
||||
'initial' => $this->user->first_name,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['last_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Last name'),
|
||||
'initial' => $this->user->last_name,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
$this->fields['password'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Your password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'help_text' => Pluf_Template::markSafe(__('Leave blank if you do not want to change your password.').'<br />'.__('Your password must be hard for other people to find it, but easy for you to remember.')),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['password2'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Confirm your password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.'));
|
||||
}
|
||||
unset($this->cleaned_data['password2']);
|
||||
if (strlen($this->cleaned_data['password']) == 0) {
|
||||
unset($this->cleaned_data['password']);
|
||||
}
|
||||
$this->user->setFromFormData($this->cleaned_data);
|
||||
if ($commit) {
|
||||
$this->user->update();
|
||||
}
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the 2 passwords are the same.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if (!isset($this->errors['password'])
|
||||
&& !isset($this->errors['password2'])) {
|
||||
$password1 = $this->cleaned_data['password'];
|
||||
$password2 = $this->cleaned_data['password2'];
|
||||
if ($password1 != $password2) {
|
||||
throw new Pluf_Form_Invalid(__('The passwords do not match. Please give them again.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
}
|
@@ -132,11 +132,16 @@ class IDF_Issue extends Pluf_Model
|
||||
|
||||
function _toIndex()
|
||||
{
|
||||
return '';
|
||||
$r = array();
|
||||
foreach ($this->get_comments_list() as $c) {
|
||||
$r[] = $c->_toIndex();
|
||||
}
|
||||
$str = str_repeat($this->summary.' ', 4).' '.implode(' ', $r);
|
||||
return Pluf_Text::cleanString(html_entity_decode($str, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
|
||||
function preSave()
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
@@ -144,15 +149,8 @@ class IDF_Issue extends Pluf_Model
|
||||
$this->modif_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function postSave()
|
||||
function postSave($create=false)
|
||||
{
|
||||
// This will be used to fire the indexing or send a
|
||||
// notification email to the interested people, etc.
|
||||
$q = new Pluf_Queue();
|
||||
$q->model_class = __CLASS__;
|
||||
$q->model_id = $this->id;
|
||||
$q->action = 'updated';
|
||||
$q->lock = 0;
|
||||
$q->create();
|
||||
IDF_Search::index($this);
|
||||
}
|
||||
}
|
@@ -90,7 +90,7 @@ class IDF_IssueComment extends Pluf_Model
|
||||
|
||||
function changedIssue()
|
||||
{
|
||||
return count($this->changes) > 0;
|
||||
return (is_array($this->changes) and count($this->changes) > 0);
|
||||
}
|
||||
|
||||
function _toIndex()
|
||||
@@ -98,27 +98,14 @@ class IDF_IssueComment extends Pluf_Model
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
function preSave()
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
|
||||
function postSave()
|
||||
function postSave($create=false)
|
||||
{
|
||||
// This will be used to fire the indexing or send a
|
||||
// notification email to the interested people, etc.
|
||||
$q = new Pluf_Queue();
|
||||
$q->model_class = __CLASS__;
|
||||
$q->model_id = $this->id;
|
||||
$q->action = 'updated';
|
||||
$q->lock = 0;
|
||||
$q->create();
|
||||
}
|
||||
}
|
||||
|
||||
function IDF_IssueComment_Filter($text)
|
||||
{
|
||||
return wordwrap($text, 80, "\n", true);
|
||||
}
|
@@ -24,6 +24,7 @@
|
||||
/**
|
||||
* Project middleware.
|
||||
*
|
||||
* It must be after the session middleware.
|
||||
*/
|
||||
class IDF_Middleware
|
||||
{
|
||||
@@ -44,7 +45,20 @@ class IDF_Middleware
|
||||
{
|
||||
$match = array();
|
||||
if (preg_match('#^/p/(\w+)/#', $request->query, $match)) {
|
||||
$request->project = IDF_Project::getOr404($match[1]);
|
||||
try {
|
||||
$request->project = IDF_Project::getOr404($match[1]);
|
||||
} catch (Pluf_HTTP_Error404 $e) {
|
||||
return new Pluf_HTTP_Response_NotFound(sprintf(__('The page <em>%s</em> was not found on the server.'), htmlspecialchars($request->query)));
|
||||
}
|
||||
$request->conf = new IDF_Conf();
|
||||
$request->conf->setProject($request->project);
|
||||
$ak = array('downloads_access_rights' => 'hasDownloadsAccess',
|
||||
'source_access_rights' => 'hasSourceAccess',
|
||||
'issues_access_rights' => 'hasIssuesAccess');
|
||||
$request->rights = array();
|
||||
foreach ($ak as $key=>$val) {
|
||||
$request->rights[$val] = (true === IDF_Precondition::accessTabGeneric($request, $key));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -54,12 +68,14 @@ class IDF_Middleware
|
||||
function IDF_Middleware_ContextPreProcessor($request)
|
||||
{
|
||||
$c = array();
|
||||
$c['request'] = $request;
|
||||
if (isset($request->project)) {
|
||||
$c['project'] = $request->project;
|
||||
$c['isOwner'] = $request->user->hasPerm('IDF.project-owner',
|
||||
$request->project);
|
||||
$c['isMember'] = $request->user->hasPerm('IDF.project-member',
|
||||
$request->project);
|
||||
$c = array_merge($c, $request->rights);
|
||||
}
|
||||
return $c;
|
||||
}
|
||||
|
52
src/IDF/Migrations/1Download.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?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 download of files.
|
||||
*/
|
||||
|
||||
function IDF_Migrations_1Download_up($params=null)
|
||||
{
|
||||
$models = array(
|
||||
'IDF_Upload',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
foreach ($models as $model) {
|
||||
$schema->model = new $model();
|
||||
$schema->createTables();
|
||||
}
|
||||
}
|
||||
|
||||
function IDF_Migrations_1Download_down($params=null)
|
||||
{
|
||||
$models = array(
|
||||
'IDF_Upload',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
foreach ($models as $model) {
|
||||
$schema->model = new $model();
|
||||
$schema->dropTables();
|
||||
}
|
||||
}
|
55
src/IDF/Migrations/2Search.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 download of files.
|
||||
*/
|
||||
|
||||
function IDF_Migrations_2Search_up($params=null)
|
||||
{
|
||||
$models = array(
|
||||
'IDF_Search_Occ',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
foreach ($models as $model) {
|
||||
$schema->model = new $model();
|
||||
$schema->createTables();
|
||||
}
|
||||
foreach (Pluf::factory('IDF_Issue')->getList() as $i) {
|
||||
IDF_Search::index($i);
|
||||
}
|
||||
}
|
||||
|
||||
function IDF_Migrations_2Search_down($params=null)
|
||||
{
|
||||
$models = array(
|
||||
'IDF_Search_Occ',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
foreach ($models as $model) {
|
||||
$schema->model = new $model();
|
||||
$schema->dropTables();
|
||||
}
|
||||
}
|
@@ -35,6 +35,8 @@ function IDF_Migrations_Install_setup($params=null)
|
||||
'IDF_Issue',
|
||||
'IDF_IssueComment',
|
||||
'IDF_Conf',
|
||||
'IDF_Upload',
|
||||
'IDF_Search_Occ',
|
||||
);
|
||||
$db = Pluf::db();
|
||||
$schema = new Pluf_DB_Schema($db);
|
||||
@@ -64,6 +66,8 @@ function IDF_Migrations_Install_teardown($params=null)
|
||||
$perm = Pluf_Permission::getFromString('IDF.project-owner');
|
||||
if ($perm) $perm->delete();
|
||||
$models = array(
|
||||
'IDF_Search_Occ',
|
||||
'IDF_Upload',
|
||||
'IDF_Conf',
|
||||
'IDF_IssueComment',
|
||||
'IDF_Issue',
|
||||
|
@@ -40,4 +40,74 @@ class IDF_Precondition
|
||||
}
|
||||
return new Pluf_HTTP_Response_Forbidden($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user is project owner or member.
|
||||
*
|
||||
* @param Pluf_HTTP_Request
|
||||
* @return mixed
|
||||
*/
|
||||
static public function projectMemberOrOwner($request)
|
||||
{
|
||||
$res = Pluf_Precondition::loginRequired($request);
|
||||
if (true !== $res) {
|
||||
return $res;
|
||||
}
|
||||
if ($request->user->hasPerm('IDF.project-owner', $request->project)
|
||||
or
|
||||
$request->user->hasPerm('IDF.project-member', $request->project)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return new Pluf_HTTP_Response_Forbidden($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user can access a given element.
|
||||
*
|
||||
* The rights are:
|
||||
* - 'all' (default)
|
||||
* - 'none'
|
||||
* - 'login'
|
||||
* - 'members'
|
||||
* - 'owners'
|
||||
*
|
||||
* The order of the rights is such that a 'owner' is also a
|
||||
* 'member' and of course a logged in person.
|
||||
*
|
||||
* @param Pluf_HTTP_Request
|
||||
* @param string Control key
|
||||
* @return mixed
|
||||
*/
|
||||
static public function accessTabGeneric($request, $key)
|
||||
{
|
||||
switch ($request->conf->getVal($key, 'all')) {
|
||||
case 'none':
|
||||
return new Pluf_HTTP_Response_Forbidden($request);
|
||||
case 'login':
|
||||
return Pluf_Precondition::loginRequired($request);
|
||||
case 'members':
|
||||
return self::projectMemberOrOwner($request);
|
||||
case 'owners':
|
||||
return self::projectOwner($request);
|
||||
case 'all':
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static public function accessSource($request)
|
||||
{
|
||||
return self::accessTabGeneric($request, 'source_access_rights');
|
||||
}
|
||||
|
||||
static public function accessIssues($request)
|
||||
{
|
||||
return self::accessTabGeneric($request, 'issues_access_rights');
|
||||
}
|
||||
|
||||
static public function accessDownloads($request)
|
||||
{
|
||||
return self::accessTabGeneric($request, 'downloads_access_rights');
|
||||
}
|
||||
}
|
@@ -31,9 +31,11 @@ class IDF_Project extends Pluf_Model
|
||||
{
|
||||
public $_model = __CLASS__;
|
||||
public $_extra_cache = array();
|
||||
protected $_pconf = null;
|
||||
|
||||
function init()
|
||||
{
|
||||
$this->_pconf = null;
|
||||
$this->_extra_cache = array();
|
||||
$this->_a['table'] = 'idf_projects';
|
||||
$this->_a['model'] = __CLASS__;
|
||||
@@ -89,8 +91,8 @@ class IDF_Project extends Pluf_Model
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
function preSave()
|
||||
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
@@ -191,8 +193,7 @@ class IDF_Project extends Pluf_Model
|
||||
*/
|
||||
public function getTagsFromConfig($cfg_key, $default, $dclass='Other')
|
||||
{
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this);
|
||||
$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);
|
||||
@@ -263,22 +264,37 @@ class IDF_Project extends Pluf_Model
|
||||
*
|
||||
* Return an array of tags sorted class, then name. Each tag get
|
||||
* the extra property 'nb_use' for the number of use in the
|
||||
* project. Only open issues are used to generate the cloud.
|
||||
* project. For issues, only open issues are used to generate the
|
||||
* cloud.
|
||||
*
|
||||
* @param string ('issues') 'closed_issues' or 'downloads'
|
||||
* @return ArrayObject of IDF_Tag
|
||||
*/
|
||||
public function getTagCloud()
|
||||
public function getTagCloud($what='issues')
|
||||
{
|
||||
$tag_t = Pluf::factory('IDF_Tag')->getSqlTable();
|
||||
$issue_t = Pluf::factory('IDF_Issue')->getSqlTable();
|
||||
$asso_t = $this->_con->pfx.'idf_issue_idf_tag_assoc';
|
||||
$ostatus = $this->getTagIdsByStatus('open');
|
||||
if (count($ostatus) == 0) $ostatus[] = 0;
|
||||
$sql = sprintf('SELECT '.$tag_t.'.id AS id, COUNT(*) AS nb_use FROM '.$tag_t.' '."\n".
|
||||
if ($what == 'issues' or $what == 'closed_issues') {
|
||||
$what_t = Pluf::factory('IDF_Issue')->getSqlTable();
|
||||
$asso_t = $this->_con->pfx.'idf_issue_idf_tag_assoc';
|
||||
if ($what == 'issues') {
|
||||
$ostatus = $this->getTagIdsByStatus('open');
|
||||
} else {
|
||||
$ostatus = $this->getTagIdsByStatus('closed');
|
||||
}
|
||||
if (count($ostatus) == 0) $ostatus[] = 0;
|
||||
$sql = sprintf('SELECT '.$tag_t.'.id AS id, COUNT(*) AS nb_use FROM '.$tag_t.' '."\n".
|
||||
'LEFT JOIN '.$asso_t.' ON idf_tag_id='.$tag_t.'.id '."\n".
|
||||
'LEFT JOIN '.$issue_t.' ON idf_issue_id='.$issue_t.'.id '."\n".
|
||||
'WHERE idf_tag_id NOT NULL AND '.$issue_t.'.status IN (%s) AND '.$issue_t.'.project='.$this->id.' GROUP BY '.$tag_t.'.id ORDER BY '.$tag_t.'.class ASC, '.$tag_t.'.name ASC',
|
||||
'LEFT JOIN '.$what_t.' ON idf_issue_id='.$what_t.'.id '."\n".
|
||||
'WHERE idf_tag_id IS NOT NULL AND '.$what_t.'.status IN (%s) AND '.$what_t.'.project='.$this->id.' GROUP BY '.$tag_t.'.id, '.$tag_t.'.class, '.$tag_t.'.name ORDER BY '.$tag_t.'.class ASC, '.$tag_t.'.name ASC',
|
||||
implode(', ', $ostatus));
|
||||
} else {
|
||||
$what_t = Pluf::factory('IDF_Upload')->getSqlTable();
|
||||
$asso_t = $this->_con->pfx.'idf_tag_idf_upload_assoc';
|
||||
$sql = 'SELECT '.$tag_t.'.id AS id, COUNT(*) AS nb_use FROM '.$tag_t.' '."\n".
|
||||
'LEFT JOIN '.$asso_t.' ON idf_tag_id='.$tag_t.'.id '."\n".
|
||||
'LEFT JOIN '.$what_t.' ON idf_upload_id='.$what_t.'.id '."\n".
|
||||
'WHERE idf_tag_id IS NOT NULL AND '.$what_t.'.project='.$this->id.' GROUP BY '.$tag_t.'.id, '.$tag_t.'.class, '.$tag_t.'.name ORDER BY '.$tag_t.'.class ASC, '.$tag_t.'.name ASC';
|
||||
}
|
||||
$tags = array();
|
||||
foreach ($this->_con->select($sql) as $idc) {
|
||||
$tag = new IDF_Tag($idc['id']);
|
||||
@@ -287,4 +303,61 @@ class IDF_Project extends Pluf_Model
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remote access url to the repository.
|
||||
*
|
||||
*/
|
||||
public function getRemoteAccessUrl()
|
||||
{
|
||||
$conf = $this->getConf();
|
||||
$scm = $conf->getVal('scm', 'git');
|
||||
$scms = Pluf::f('allowed_scm');
|
||||
return call_user_func(array($scms[$scm], 'getRemoteAccessUrl'),
|
||||
$this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root name of the project scm
|
||||
*
|
||||
* @return string SCM root
|
||||
*/
|
||||
public function getScmRoot()
|
||||
{
|
||||
$conf = $this->getConf();
|
||||
$roots = array('git' => 'master', 'svn' => 'HEAD');
|
||||
$scm = $conf->getVal('scm', 'git');
|
||||
return $roots[$scm];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the object belongs to the project or rise a 404
|
||||
* error.
|
||||
*
|
||||
* By convention, all the objects belonging to a project have the
|
||||
* 'project' property set, so this is easy to check.
|
||||
*
|
||||
* @param Pluf_Model
|
||||
*/
|
||||
public function inOr404($obj)
|
||||
{
|
||||
if ($obj->project != $this->id) {
|
||||
throw new Pluf_HTTP_Error404();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to get a configuration object.
|
||||
*
|
||||
* @return IDF_Conf
|
||||
*/
|
||||
public function getConf()
|
||||
{
|
||||
if ($this->_pconf == null) {
|
||||
$this->_pconf = new IDF_Conf();
|
||||
$this->_pconf->setProject($this);
|
||||
}
|
||||
return $this->_pconf;
|
||||
}
|
||||
|
||||
}
|
44
src/IDF/Scm.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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 ***** */
|
||||
|
||||
/**
|
||||
* Manage differents SCM systems
|
||||
*/
|
||||
class IDF_Scm
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns an instance of the correct scm backend object.
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
public static function get($request=null)
|
||||
{
|
||||
// Get scm type from project conf ; defaults to git
|
||||
$scm = $request->conf->getVal('scm', 'git');
|
||||
$scms = Pluf::f('allowed_scm');
|
||||
return call_user_func(array($scms[$scm], 'factory'),
|
||||
$request->project);
|
||||
}
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@
|
||||
* Git utils.
|
||||
*
|
||||
*/
|
||||
class IDF_Git
|
||||
class IDF_Scm_Git
|
||||
{
|
||||
public $repo = '';
|
||||
public $mediumtree_fmt = 'commit %H%nAuthor: %an <%ae>%nTree: %T%nDate: %ai%n%n%s%n%n%b';
|
||||
@@ -35,14 +35,44 @@ class IDF_Git
|
||||
$this->repo = $repo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of the git daemon.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return string URL
|
||||
*/
|
||||
public static function getRemoteAccessUrl($project)
|
||||
{
|
||||
$url = Pluf::f('git_remote_url');
|
||||
if (Pluf::f('git_repositories_unique', true)) {
|
||||
return $url;
|
||||
}
|
||||
return $url.'/'.$project->shortname.'.git';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this object correctly initialized for the project.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return IDF_Scm_Git
|
||||
*/
|
||||
public static function factory($project)
|
||||
{
|
||||
$rep = Pluf::f('git_repositories');
|
||||
if (false == Pluf::f('git_repositories_unique', false)) {
|
||||
$rep = $rep.'/'.$project->shortname.'.git';
|
||||
}
|
||||
return new IDF_Scm_Git($rep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a given object hash.
|
||||
*
|
||||
* @param string Object hash.
|
||||
* @param null to be svn client compatible
|
||||
* @return mixed false if not valid or 'blob', 'tree', 'commit'
|
||||
*/
|
||||
public function testHash($hash)
|
||||
public function testHash($hash, $dummy=null)
|
||||
{
|
||||
$cmd = sprintf('GIT_DIR=%s git cat-file -t %s',
|
||||
escapeshellarg($this->repo),
|
||||
@@ -297,8 +327,24 @@ class IDF_Git
|
||||
}
|
||||
}
|
||||
$c['full_message'] = trim($c['full_message']);
|
||||
|
||||
$res[] = (object) $c;
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the command to create a zip archive at a given commit.
|
||||
*
|
||||
* @param string Commit
|
||||
* @param string Prefix ('git-repo-dump')
|
||||
* @return string Command
|
||||
*/
|
||||
public function getArchiveCommand($commit, $prefix='git-repo-dump/')
|
||||
{
|
||||
return sprintf('GIT_DIR=%s git archive --format=zip --prefix=%s %s',
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($prefix),
|
||||
escapeshellarg($commit));
|
||||
}
|
||||
|
||||
}
|
425
src/IDF/Scm/Svn.php
Normal file
@@ -0,0 +1,425 @@
|
||||
<?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 ***** */
|
||||
|
||||
/**
|
||||
* SVN utils.
|
||||
*
|
||||
*/
|
||||
class IDF_Scm_Svn
|
||||
{
|
||||
public $repo = '';
|
||||
public $username = '';
|
||||
public $password = '';
|
||||
private $assoc = array('dir' => 'tree',
|
||||
'file' => 'blob');
|
||||
|
||||
|
||||
public function __construct($repo, $username='', $password='')
|
||||
{
|
||||
$this->repo = $repo;
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of the subversion repository.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return string URL
|
||||
*/
|
||||
public static function getRemoteAccessUrl($project)
|
||||
{
|
||||
$conf = $project->getConf();
|
||||
if (false !== ($url=$conf->getVal('svn_remote_url', false))) {
|
||||
// Remote repository
|
||||
return $url;
|
||||
}
|
||||
$url = Pluf::f('svn_remote_url');
|
||||
if (Pluf::f('svn_repositories_unique', true)) {
|
||||
return $url;
|
||||
}
|
||||
return $url.'/'.$project->shortname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this object correctly initialized for the project.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return IDF_Scm_Svn
|
||||
*/
|
||||
public static function factory($project)
|
||||
{
|
||||
$conf = $project->getConf();
|
||||
// Find the repository
|
||||
if (false !== ($rep=$conf->getVal('svn_remote_url', false))) {
|
||||
// Remote repository
|
||||
return new IDF_Scm_Svn($rep,
|
||||
$conf->getVal('svn_username'),
|
||||
$conf->getVal('svn_password'));
|
||||
} else {
|
||||
$rep = Pluf::f('svn_repositories');
|
||||
if (false == Pluf::f('svn_repositories_unique', false)) {
|
||||
$rep = $rep.'/'.$project->shortname;
|
||||
}
|
||||
return new IDF_Scm_Svn($rep);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a given object hash.
|
||||
*
|
||||
* @param string Object hash.
|
||||
* @return mixed false if not valid or 'blob', 'tree', 'commit'
|
||||
*/
|
||||
public function testHash($rev, $path='')
|
||||
{
|
||||
// OK if HEAD on /
|
||||
if ($rev === 'HEAD' && $path === '') {
|
||||
return 'commit';
|
||||
}
|
||||
|
||||
// Else, test the path on revision
|
||||
$cmd = sprintf('svn info --xml --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$path),
|
||||
escapeshellarg($rev));
|
||||
$xmlInfo = shell_exec($cmd);
|
||||
|
||||
// If exception is thrown, return false
|
||||
try {
|
||||
$xml = simplexml_load_string($xmlInfo);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the entry node does exists, params are wrong
|
||||
if (!isset($xml->entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Else, enjoy it :)
|
||||
return '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($rev='HEAD', $folder='')
|
||||
{
|
||||
$cmd = sprintf('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);
|
||||
$res = array();
|
||||
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['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);
|
||||
|
||||
// Get the size if the type is blob
|
||||
if ($file['type'] == 'blob') {
|
||||
$file['size'] = (string) $entry->size;
|
||||
}
|
||||
|
||||
$file['perm'] = '';
|
||||
|
||||
$res[] = (object) $file;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a commit message for given file and revision.
|
||||
*
|
||||
* @param string File
|
||||
* @param string Commit ('HEAD')
|
||||
*
|
||||
* @return String commit message
|
||||
*/
|
||||
private function getCommitMessage($file, $rev='HEAD')
|
||||
{
|
||||
$cmd = sprintf('svn log --xml --limit 1 --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($file),
|
||||
escapeshellarg($rev));
|
||||
$xmlLog = shell_exec($cmd);
|
||||
$xml = simplexml_load_string($xmlLog);
|
||||
return (string) $xml->logentry->msg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the file info.
|
||||
*
|
||||
* @param string File
|
||||
* @param string Commit ('HEAD')
|
||||
* @return false Information
|
||||
*/
|
||||
public function getFileInfo($totest, $rev='HEAD')
|
||||
{
|
||||
$cmd = sprintf('svn info --xml --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$totest),
|
||||
escapeshellarg($rev));
|
||||
$xmlInfo = shell_exec($cmd);
|
||||
$xml = simplexml_load_string($xmlInfo);
|
||||
$entry = $xml->entry;
|
||||
|
||||
$file = array();
|
||||
$file['fullpath'] = $totest;
|
||||
$file['hash'] = (string) $entry->repository->uuid;
|
||||
$file['type'] = $this->assoc[(string) $entry['kind']];
|
||||
$file['file'] = $totest;
|
||||
$file['rev'] = (string) $entry->commit['revision'];
|
||||
$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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a blob.
|
||||
*
|
||||
* @param string Blob hash
|
||||
* @return string Raw blob
|
||||
*/
|
||||
public function getBlob($path, $rev)
|
||||
{
|
||||
$cmd = sprintf('svn cat --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$path),
|
||||
escapeshellarg($rev));
|
||||
return shell_exec($cmd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the branches.
|
||||
*
|
||||
* @return array Branches.
|
||||
*/
|
||||
public function getBranches()
|
||||
{
|
||||
$res = array('HEAD');
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get commit details.
|
||||
*
|
||||
* @param string Commit ('HEAD').
|
||||
* @return array Changes.
|
||||
*/
|
||||
public function getCommit($rev='HEAD')
|
||||
{
|
||||
$res = array();
|
||||
$cmd = sprintf('svn log --xml -v --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($rev));
|
||||
$xmlRes = shell_exec($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'] = $this->getDiff($rev);
|
||||
$res['tree'] = '';
|
||||
|
||||
|
||||
return (object) $res;
|
||||
}
|
||||
|
||||
private function getDiff($rev='HEAD')
|
||||
{
|
||||
$res = array();
|
||||
$cmd = sprintf('svn diff -c %s --username=%s --password=%s %s',
|
||||
escapeshellarg($rev),
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo));
|
||||
return shell_exec($cmd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get latest changes.
|
||||
*
|
||||
* @param string Commit ('HEAD').
|
||||
* @param int Number of changes (10).
|
||||
*
|
||||
* @return array Changes.
|
||||
*/
|
||||
public function getChangeLog($rev='HEAD', $n=10)
|
||||
{
|
||||
$res = array();
|
||||
$cmd = sprintf('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);
|
||||
$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;
|
||||
$log['commit'] = (string) $entry['revision'];
|
||||
$log['full_message'] = '';
|
||||
|
||||
$res[] = (object) $log;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate the command to create a zip archive at a given commit.
|
||||
* Unsupported feature in subversion
|
||||
*
|
||||
* @param string dummy
|
||||
* @param string dummy
|
||||
* @return Exception
|
||||
*/
|
||||
public function getArchiveCommand($commit, $prefix='git-repo-dump/')
|
||||
{
|
||||
throw new Exception(('Unsupported feature.'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get additionnals properties on path and revision
|
||||
*
|
||||
* @param string File
|
||||
* @param string Commit ('HEAD')
|
||||
* @return array
|
||||
*/
|
||||
public function getProperties($rev, $path='')
|
||||
{
|
||||
$res = array();
|
||||
$cmd = sprintf('svn proplist --xml --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$path),
|
||||
escapeshellarg($rev));
|
||||
$xmlProps = shell_exec($cmd);
|
||||
$props = simplexml_load_string($xmlProps);
|
||||
|
||||
// No properties, returns an empty array
|
||||
if (!isset($props->target)) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
// Get the value of each property
|
||||
foreach ($props->target->property as $prop) {
|
||||
$key = (string) $prop['name'];
|
||||
$res[$key] = $this->getProperty($key, $rev, $path);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a specific additionnal property on path and revision
|
||||
*
|
||||
* @param string Property
|
||||
* @param string File
|
||||
* @param string Commit ('HEAD')
|
||||
* @return string the property value
|
||||
*/
|
||||
private function getProperty($property, $rev, $path='')
|
||||
{
|
||||
$res = array();
|
||||
$cmd = sprintf('svn propget --xml %s --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($property),
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo.'/'.$path),
|
||||
escapeshellarg($rev));
|
||||
$xmlProp = shell_exec($cmd);
|
||||
$prop = simplexml_load_string($xmlProp);
|
||||
|
||||
return (string) $prop->target->property;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of the last commit in the repository.
|
||||
*
|
||||
* @param string Commit ('HEAD').
|
||||
*
|
||||
* @return String last number commit
|
||||
*/
|
||||
public function getLastCommit($rev='HEAD')
|
||||
{
|
||||
$xmlInfo = '';
|
||||
$cmd = sprintf('svn info --xml --username=%s --password=%s %s@%s',
|
||||
escapeshellarg($this->username),
|
||||
escapeshellarg($this->password),
|
||||
escapeshellarg($this->repo),
|
||||
escapeshellarg($rev));
|
||||
$xmlInfo = shell_exec($cmd);
|
||||
|
||||
$xml = simplexml_load_string($xmlInfo);
|
||||
return (string) $xml->entry->commit['revision'];
|
||||
}
|
||||
}
|
||||
|
160
src/IDF/Search.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?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
|
||||
#
|
||||
# Based on work under GNU LGPL copyright, from the Pluf Framework
|
||||
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Class implementing the search engine
|
||||
*
|
||||
* It is a modified version of the Pluf_Search class to be able to
|
||||
* cluster the results by project.
|
||||
*/
|
||||
class IDF_Search extends Pluf_Search
|
||||
{
|
||||
/**
|
||||
* Search.
|
||||
*
|
||||
* Returns an array of array with model_class, model_id and
|
||||
* score. The list is already sorted by score descending.
|
||||
*
|
||||
* You can then filter the list as you wish with another set of
|
||||
* weights.
|
||||
*
|
||||
* @param string Query string.
|
||||
* @param int Project id to limit the results (null)
|
||||
* @param string Stemmer class.
|
||||
* @return array Results.
|
||||
*/
|
||||
public static function mySearch($query, $project=null, $stemmer='Pluf_Text_Stemmer_Porter')
|
||||
{
|
||||
$query = Pluf_Text::cleanString(html_entity_decode($query, ENT_QUOTES, 'UTF-8'));
|
||||
$words = Pluf_Text::tokenize($query);
|
||||
if ($stemmer != null) {
|
||||
$words = self::stem($words, $stemmer);
|
||||
}
|
||||
$words_flat = array();
|
||||
foreach ($words as $word=>$c) {
|
||||
$words_flat[] = $word;
|
||||
}
|
||||
$word_ids = self::getWordIds($words_flat);
|
||||
if (in_array(null, $word_ids)) {
|
||||
return array();
|
||||
}
|
||||
return self::mySearchDocuments($word_ids, $project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search documents.
|
||||
*
|
||||
* Only the total of the ponderated occurences is used to sort the
|
||||
* results.
|
||||
*
|
||||
* @param array Ids.
|
||||
* @param IDF_Project Project to limit the search.
|
||||
* @return array Sorted by score, returns model_class, model_id and score.
|
||||
*/
|
||||
public static function mySearchDocuments($wids, $project)
|
||||
{
|
||||
$db =& Pluf::db();
|
||||
$gocc = new IDF_Search_Occ();
|
||||
$where = array();
|
||||
foreach ($wids as $id) {
|
||||
$where[] = $db->qn('word').'='.(int)$id;
|
||||
}
|
||||
$prj = (is_null($project)) ? '' : ' AND project='.(int)$project->id;
|
||||
$select = 'SELECT model_class, model_id, SUM(pondocc) AS score FROM '.$gocc->getSqlTable().' WHERE '.implode(' OR ', $where).$prj.' GROUP BY model_class, model_id HAVING COUNT(*)='.count($wids).' ORDER BY score DESC';
|
||||
return $db->select($select);
|
||||
}
|
||||
|
||||
/**
|
||||
* Index a document.
|
||||
*
|
||||
* See Pluf_Search for the disclaimer and informations.
|
||||
*
|
||||
* @param Pluf_Model Document to index.
|
||||
* @param Stemmer used. ('Pluf_Text_Stemmer_Porter')
|
||||
* @return array Statistics.
|
||||
*/
|
||||
public static function index($doc, $stemmer='Pluf_Text_Stemmer_Porter')
|
||||
{
|
||||
$words = Pluf_Text::tokenize($doc->_toIndex());
|
||||
if ($stemmer != null) {
|
||||
$words = self::stem($words, $stemmer);
|
||||
}
|
||||
// Get the total number of words.
|
||||
$total = 0.0;
|
||||
$words_flat = array();
|
||||
foreach ($words as $word => $occ) {
|
||||
$total += (float) $occ;
|
||||
$words_flat[] = $word;
|
||||
}
|
||||
// Drop the last indexation.
|
||||
$gocc = new IDF_Search_Occ();
|
||||
$sql = new Pluf_SQL('DELETE FROM '.$gocc->getSqlTable().' WHERE model_class=%s AND model_id=%s', array($doc->_model, $doc->id));
|
||||
$db =& Pluf::db();
|
||||
$db->execute($sql->gen());
|
||||
// Get the ids for each word.
|
||||
$ids = self::getWordIds($words_flat);
|
||||
// Insert a new word for the missing words and add the occ.
|
||||
$n = count($ids);
|
||||
$new_words = 0;
|
||||
$done = array();
|
||||
for ($i=0;$i<$n;$i++) {
|
||||
if ($ids[$i] === null) {
|
||||
$word = new Pluf_Search_Word();
|
||||
$word->word = $words_flat[$i];
|
||||
$word->create();
|
||||
$ids[$i] = $word->id;
|
||||
$new_words++;
|
||||
}
|
||||
if (isset($done[$ids[$i]])) {
|
||||
continue;
|
||||
}
|
||||
$done[$ids[$i]] = true;
|
||||
$occ = new IDF_Search_Occ();
|
||||
$occ->word = new Pluf_Search_Word($ids[$i]);
|
||||
$occ->model_class = $doc->_model;
|
||||
$occ->model_id = $doc->id;
|
||||
$occ->project = $doc->get_project();
|
||||
$occ->occ = $words[$words_flat[$i]];
|
||||
$occ->pondocc = $words[$words_flat[$i]]/$total;
|
||||
$occ->create();
|
||||
}
|
||||
// update the stats
|
||||
$sql = new Pluf_SQL('model_class=%s AND model_id=%s',
|
||||
array($doc->_model, $doc->id));
|
||||
$last_index = Pluf::factory('Pluf_Search_Stats')->getList(array('filter' => $sql->gen()));
|
||||
if ($last_index->count() == 0) {
|
||||
$stats = new Pluf_Search_Stats();
|
||||
$stats->model_class = $doc->_model;
|
||||
$stats->model_id = $doc->id;
|
||||
$stats->indexations = 1;
|
||||
$stats->create();
|
||||
} else {
|
||||
$last_index[0]->indexations += 1;
|
||||
$last_index[0]->update();
|
||||
}
|
||||
return array('total' => $total, 'new' => $new_words, 'unique'=>$n);
|
||||
}
|
||||
}
|
99
src/IDF/Search/Occ.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?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 ***** */
|
||||
|
||||
/**
|
||||
* Storage of the occurence of the words.
|
||||
*/
|
||||
class IDF_Search_Occ extends Pluf_Model
|
||||
{
|
||||
public $_model = 'IDF_Search_Occ';
|
||||
|
||||
function init()
|
||||
{
|
||||
$this->_a['verbose'] = __('occurence');
|
||||
$this->_a['table'] = 'idf_search_occs';
|
||||
$this->_a['model'] = 'IDF_Search_Occ';
|
||||
$this->_a['cols'] = array(
|
||||
// It is mandatory to have an "id" column.
|
||||
'id' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Sequence',
|
||||
//It is automatically added.
|
||||
'blank' => true,
|
||||
),
|
||||
'word' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'Pluf_Search_Word',
|
||||
'blank' => false,
|
||||
'verbose' => __('word'),
|
||||
),
|
||||
'model_class' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Varchar',
|
||||
'blank' => false,
|
||||
'size' => 150,
|
||||
'verbose' => __('model class'),
|
||||
),
|
||||
'model_id' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Integer',
|
||||
'blank' => false,
|
||||
'verbose' => __('model id'),
|
||||
),
|
||||
'project' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'IDF_Project',
|
||||
'blank' => false,
|
||||
'verbose' => __('project'),
|
||||
),
|
||||
'occ' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Integer',
|
||||
'blank' => false,
|
||||
'verbose' => __('occurences'),
|
||||
),
|
||||
'pondocc' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Float',
|
||||
'blank' => false,
|
||||
'verbose' => __('ponderated occurence'),
|
||||
),
|
||||
);
|
||||
$this->_a['idx'] = array(
|
||||
'model_class_id_combo_word_idx' =>
|
||||
array(
|
||||
'type' => 'unique',
|
||||
'col' => 'model_class, model_id, word',
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function __toString()
|
||||
{
|
||||
return $this->word;
|
||||
}
|
||||
}
|
||||
|
@@ -89,7 +89,7 @@ class IDF_Tag extends Pluf_Model
|
||||
);
|
||||
}
|
||||
|
||||
function preSave()
|
||||
function preSave($create=false)
|
||||
{
|
||||
$this->lcname = mb_strtolower($this->name);
|
||||
}
|
||||
|
@@ -29,21 +29,27 @@ Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
class IDF_Template_IssueComment extends Pluf_Template_Tag
|
||||
{
|
||||
private $project = null;
|
||||
private $git = null;
|
||||
private $request = null;
|
||||
private $scm = null;
|
||||
|
||||
function start($text, $project)
|
||||
function start($text, $request)
|
||||
{
|
||||
$this->project = $project;
|
||||
$this->git = new IDF_Git(Pluf::f('git_repository'));
|
||||
$text = wordwrap($text, 80, "\n", true);
|
||||
$this->project = $request->project;
|
||||
$this->request = $request;
|
||||
$this->scm = IDF_Scm::get($request);
|
||||
$text = wordwrap($text, 69, "\n", true);
|
||||
$text = Pluf_esc($text);
|
||||
$text = ereg_replace('[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]',
|
||||
'<a href="\\0" rel="nofollow">\\0</a>',
|
||||
$text);
|
||||
$text = preg_replace_callback('#(issues?|bugs?|tickets?)\s+(\d+)((\s+and|\s+or|,)\s+(\d+)){0,}#im',
|
||||
array($this, 'callbackIssues'), $text);
|
||||
$text = preg_replace_callback('#(commit\s+)([0-9a-f]{5,40})#im',
|
||||
array($this, 'callbackCommit'), $text);
|
||||
if ($request->rights['hasIssuesAccess']) {
|
||||
$text = preg_replace_callback('#(issues?|bugs?|tickets?)\s+(\d+)((\s+and|\s+or|,)\s+(\d+)){0,}#im',
|
||||
array($this, 'callbackIssues'), $text);
|
||||
}
|
||||
if ($request->rights['hasSourceAccess']) {
|
||||
$text = preg_replace_callback('#(commit\s+)([0-9a-f]{1,40})#im',
|
||||
array($this, 'callbackCommit'), $text);
|
||||
}
|
||||
echo $text;
|
||||
}
|
||||
|
||||
@@ -84,10 +90,10 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
||||
|
||||
function callbackCommit($m)
|
||||
{
|
||||
if ($this->git->testHash($m[2]) != 'commit') {
|
||||
if ($this->scm->testHash($m[2]) != 'commit') {
|
||||
return $m[0];
|
||||
}
|
||||
$co = $this->git->getCommit($m[2]);
|
||||
$co = $this->scm->getCommit($m[2]);
|
||||
return '<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit', array($this->project->shortname, $co->commit)).'">'.$m[1].$m[2].'</a>';
|
||||
}
|
||||
|
||||
|
102
src/IDF/Template/Markdown.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?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 ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_Text_MarkDown_parse');
|
||||
|
||||
function IDF_Template_Markdown_filter($mdtext)
|
||||
{
|
||||
$filter = new IDF_Template_Markdown();
|
||||
return Pluf_Template::markSafe(Pluf_Text_MarkDown_parse($filter->go($mdtext)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Strict class to only allow entities.
|
||||
*/
|
||||
class IDF_Template_Markdown extends Pluf_Text_HTML_Filter
|
||||
{
|
||||
public $allowed = array();
|
||||
public $always_close = array();
|
||||
public $remove_blanks = array();
|
||||
public $allowed_entities = array(
|
||||
'amp',
|
||||
'gt',
|
||||
'lt',
|
||||
'quot',
|
||||
'nbsp',
|
||||
'ndash',
|
||||
'rdquo',
|
||||
'ldquo',
|
||||
'Alpha',
|
||||
'Beta',
|
||||
'Gamma',
|
||||
'Delta',
|
||||
'Epsilon',
|
||||
'Zeta',
|
||||
'Eta',
|
||||
'Theta',
|
||||
'Iota',
|
||||
'Kappa',
|
||||
'Lambda',
|
||||
'Mu',
|
||||
'Nu',
|
||||
'Xi',
|
||||
'Omicron',
|
||||
'Pi',
|
||||
'Rho',
|
||||
'Sigma',
|
||||
'Tau',
|
||||
'Upsilon',
|
||||
'Phi',
|
||||
'Chi',
|
||||
'Psi',
|
||||
'Omega',
|
||||
'alpha',
|
||||
'beta',
|
||||
'gamma',
|
||||
'delta',
|
||||
'epsilon',
|
||||
'zeta',
|
||||
'eta',
|
||||
'theta',
|
||||
'iota',
|
||||
'kappa',
|
||||
'lambda',
|
||||
'mu',
|
||||
'nu',
|
||||
'xi',
|
||||
'omicron',
|
||||
'pi',
|
||||
'rho',
|
||||
'sigmaf',
|
||||
'sigma',
|
||||
'tau',
|
||||
'upsilon',
|
||||
'phi',
|
||||
'chi',
|
||||
'psi',
|
||||
'omega',
|
||||
'thetasym',
|
||||
'upsih',
|
||||
'piv',
|
||||
);
|
||||
}
|
42
src/IDF/Tests/TestGit.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?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 ***** */
|
||||
|
||||
/**
|
||||
* Test the git class.
|
||||
*/
|
||||
class IDF_Tests_TestGit extends UnitTestCase
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('Test the git class.');
|
||||
}
|
||||
|
||||
public function testParseLog()
|
||||
{
|
||||
$log_lines = preg_split("/\015\012|\015|\012/", file_get_contents(dirname(__FILE__).'/test-log.txt'));
|
||||
$log = IDF_Git::parseLog($log_lines, 3);
|
||||
$this->assertEqual('Fixed the middleware to correctly return a 404 error if the project is', $log[0]->title);
|
||||
|
||||
}
|
||||
}
|
47
src/IDF/Tests/TestSource.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# This file is part of InDefero, an open source project management application.
|
||||
# Copyright (C) 2008 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 ***** */
|
||||
|
||||
/**
|
||||
* Test the source class.
|
||||
*/
|
||||
class IDF_Tests_TestSource extends UnitTestCase
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('Test the source class.');
|
||||
}
|
||||
|
||||
public function testGetMimeType()
|
||||
{
|
||||
$files = array(
|
||||
'whatever.php' => 'application/x-httpd-php',
|
||||
'whatever.pht' => 'application/x-httpd-php',
|
||||
'README' => 'text/plain',
|
||||
);
|
||||
foreach ($files as $file => $mime) {
|
||||
$m = IDF_Views_Source::getMimeType($file);
|
||||
$this->assertEqual($mime, $m[0]);
|
||||
}
|
||||
}
|
||||
}
|
210
src/IDF/Tests/test-log.txt
Normal file
@@ -0,0 +1,210 @@
|
||||
commit cf9360a1a87f8a98dc506a316055537b95ec245f
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sat Aug 2 09:48:55 2008 +0200
|
||||
|
||||
Fixed the middleware to correctly return a 404 error if the project is
|
||||
not found.
|
||||
|
||||
commit 953d7c4ecd37e2c89058b656ee586ae73bfe1e8f
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sat Aug 2 09:48:35 2008 +0200
|
||||
|
||||
Added the name of the login view.
|
||||
|
||||
commit f4f8f9615ab460b9966509bd60b740c84ec9ecc9
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sat Aug 2 09:42:05 2008 +0200
|
||||
|
||||
Added the link to commit and issues in the changelog.
|
||||
|
||||
commit 4c5bd8d2be673c9d86d8b6b5108d551982491d5c
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sat Aug 2 09:38:06 2008 +0200
|
||||
|
||||
Fixed bug when looking at a commit which is a merge.
|
||||
|
||||
When you merge you do not get always a diff of files. This fix correct
|
||||
that for the case of commit 9a2b8e249acad9f844.
|
||||
|
||||
commit fd6031d7f50085b2e42bb539a886fc9175f6fe27
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Aug 1 22:18:58 2008 +0200
|
||||
|
||||
Fixed SQL to follow the standards.
|
||||
|
||||
commit 83658ac860328568d8570cbbadde565de8348be9
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Aug 1 22:15:49 2008 +0200
|
||||
|
||||
Fixed to have standard SQL.
|
||||
|
||||
commit 593afd9b8b18efde2a7817d57e8f101112aaa6fe
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Aug 1 22:13:25 2008 +0200
|
||||
|
||||
Fix for PostgreSQL.
|
||||
|
||||
commit a831c749d849f903f84698c36666affd391aa04d
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Aug 1 22:03:56 2008 +0200
|
||||
|
||||
Fixed boolean for PostgreSQL.
|
||||
|
||||
commit 7d806325579547facd27a0c44b54872fe9d7fb2d
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Aug 1 00:50:44 2008 +0200
|
||||
|
||||
Added code indentation.
|
||||
|
||||
commit 80ce87009e0249b7faf1143075bb4006bd2f8e35
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Aug 1 00:38:29 2008 +0200
|
||||
|
||||
Added a better commit diff.
|
||||
|
||||
commit cb15f036fe91edb9c07ff07f13bc592a8877f3c2
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Thu Jul 31 22:54:02 2008 +0200
|
||||
|
||||
Fixed some typos.
|
||||
|
||||
commit 1b3a42940d30abb342d9c4b8ff166a586701b784
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Thu Jul 31 22:50:21 2008 +0200
|
||||
|
||||
Added the registration procedure.
|
||||
|
||||
commit 416d13e249da7d8717ebb15966b9dbbd5c0188ba
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Tue Jul 29 22:33:13 2008 +0200
|
||||
|
||||
Added the registration form.
|
||||
|
||||
Still need a lot :)
|
||||
|
||||
commit c50e218704dcc81eb346cc757e4c1bdbd0808d8b
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Tue Jul 29 21:18:02 2008 +0200
|
||||
|
||||
Added a project home.
|
||||
|
||||
commit ccf24df13120ae1e64225ec27db1ee647c9df4d4
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Tue Jul 29 15:13:40 2008 +0200
|
||||
|
||||
Link to the corresponding tree in the commit view.
|
||||
|
||||
commit a6716c77160c9bbb4829eff5c6e11c7b9a4f6d50
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Mon Jul 28 22:09:17 2008 +0200
|
||||
|
||||
Added the visualisation of a commit.
|
||||
|
||||
commit 3fb47562ce0453af4481b1b470581f5bcbbc6b3b
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Mon Jul 28 20:31:23 2008 +0200
|
||||
|
||||
Automatically create links in the issue description and comments.
|
||||
|
||||
Link to issues but also commits.
|
||||
|
||||
commit 3dbae6272a9f239499038f069f6472dfceb5e73e
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sun Jul 27 21:38:49 2008 +0200
|
||||
|
||||
Added smooth handling of bad files and commits.
|
||||
|
||||
Now simply redirect to the root of the first available branch.
|
||||
|
||||
commit 8a0a35726cd82e3003675d8ba432efe68f7c4f74
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sun Jul 27 17:46:04 2008 +0200
|
||||
|
||||
Fixed typo.
|
||||
|
||||
commit b6084cbf070bf9e78101b1088d5d6c0d852ed6dc
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sun Jul 27 17:43:51 2008 +0200
|
||||
|
||||
Improved the support of the git browser.
|
||||
|
||||
Now the reference is always a commit as from a commit it is always possible to travel back to the corresponding tree and blobs.
|
||||
|
||||
commit 9a2b8e249acad9f84401846cf87bf040ffd585b3
|
||||
Merge: 789c7ed... 24e8c80...
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sun Jul 27 01:51:55 2008 +0200
|
||||
|
||||
Merge branch 'gitbrowser'
|
||||
|
||||
commit 789c7ed43d2b551ba9de97dc8af87cb8d6fa208c
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sun Jul 27 01:51:08 2008 +0200
|
||||
|
||||
Take into account if in one branch but listing another.
|
||||
|
||||
Need to check how this is working on a bar repository.
|
||||
|
||||
commit 24e8c80dfbd358710464cda0e5570655d5f200c6
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sun Jul 27 01:37:43 2008 +0200
|
||||
|
||||
Updated the docstring.
|
||||
|
||||
commit c915f8fccfc20a1a491bb88dd7848005dc1641ff
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sun Jul 27 01:31:10 2008 +0200
|
||||
|
||||
Added the changelog and fixed the source browser.
|
||||
|
||||
The source browser is normally a little bit more robust.
|
||||
|
||||
commit f57a0ec08bfbaa830f4f7fb39f1f7e39d400ecb3
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sat Jul 26 20:17:18 2008 +0200
|
||||
|
||||
Cosmetic improvements.
|
||||
|
||||
commit 876e206742179ba640667430b5cad6b45c651250
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Sat Jul 26 18:42:41 2008 +0200
|
||||
|
||||
First work on the git browser.
|
||||
|
||||
commit 2e711bee8d2b7c6680d6d44cb796f2cc67c9ed68
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Jul 25 14:25:50 2008 +0200
|
||||
|
||||
Added a nice formatting of the issue comments.
|
||||
|
||||
commit 4eea3797b26cb3ab34c5b4e1b7ff5098f2284deb
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Jul 25 14:15:58 2008 +0200
|
||||
|
||||
Added the autocompletion of the owner and cosmetic changes.
|
||||
|
||||
commit e5d296d8638db9bd59a85360d80e126b901befeb
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Jul 25 11:17:56 2008 +0200
|
||||
|
||||
Added the Shift+w hotkey to get the working list of the user.
|
||||
|
||||
commit d19dbb441c86740d6a2df2501cb5875a5fc34e19
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Jul 25 11:16:18 2008 +0200
|
||||
|
||||
Added a hotkey tag to easily add them.
|
||||
|
||||
Added a new Shift+m hotkey to access the list of submitted issues.
|
||||
|
||||
commit cc5ec30e6a06a3c855848b907512e4b796950981
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Jul 25 10:28:35 2008 +0200
|
||||
|
||||
Correctly set the copyrights.
|
||||
|
||||
commit efbd82fccb20b0b4c9ac82777b8bdf7d83be0e40
|
||||
Author: Loic d'Anterroches <titoo@users.sourceforge.net>
|
||||
Date: Fri Jul 25 10:26:05 2008 +0200
|
||||
|
||||
Initial commit.
|
148
src/IDF/Upload.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?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 ***** */
|
||||
|
||||
/**
|
||||
* File upload.
|
||||
*
|
||||
* You can set labels on files.
|
||||
*/
|
||||
class IDF_Upload extends Pluf_Model
|
||||
{
|
||||
public $_model = __CLASS__;
|
||||
|
||||
function init()
|
||||
{
|
||||
$this->_a['table'] = 'idf_uploads';
|
||||
$this->_a['model'] = __CLASS__;
|
||||
$this->_a['cols'] = array(
|
||||
// It is mandatory to have an "id" column.
|
||||
'id' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Sequence',
|
||||
'blank' => true,
|
||||
),
|
||||
'project' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'IDF_Project',
|
||||
'blank' => false,
|
||||
'verbose' => __('project'),
|
||||
'relate_name' => 'issues',
|
||||
),
|
||||
'summary' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Varchar',
|
||||
'blank' => false,
|
||||
'size' => 250,
|
||||
'verbose' => __('summary'),
|
||||
),
|
||||
'file' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_File',
|
||||
'blank' => false,
|
||||
'default' => 0,
|
||||
'verbose' => __('file'),
|
||||
'help_text' => __('The path is relative to the upload path.'),
|
||||
),
|
||||
'filesize' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Integer',
|
||||
'blank' => false,
|
||||
'default' => 0,
|
||||
'verbose' => __('file size in bytes'),
|
||||
),
|
||||
'submitter' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||
'model' => 'Pluf_User',
|
||||
'blank' => false,
|
||||
'verbose' => __('submitter'),
|
||||
'relate_name' => 'submitted_issue',
|
||||
),
|
||||
'tags' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Manytomany',
|
||||
'blank' => true,
|
||||
'model' => 'IDF_Tag',
|
||||
'verbose' => __('labels'),
|
||||
),
|
||||
'downloads' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Integer',
|
||||
'blank' => false,
|
||||
'default' => 0,
|
||||
'verbose' => __('number of downloads'),
|
||||
),
|
||||
'creation_dtime' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Datetime',
|
||||
'blank' => true,
|
||||
'verbose' => __('creation date'),
|
||||
),
|
||||
'modif_dtime' =>
|
||||
array(
|
||||
'type' => 'Pluf_DB_Field_Datetime',
|
||||
'blank' => true,
|
||||
'verbose' => __('modification date'),
|
||||
),
|
||||
);
|
||||
$this->_a['idx'] = array(
|
||||
'modif_dtime_idx' =>
|
||||
array(
|
||||
'col' => 'modif_dtime',
|
||||
'type' => 'normal',
|
||||
),
|
||||
);
|
||||
$table = $this->_con->pfx.'idf_tag_idf_upload_assoc';
|
||||
$this->_a['views'] = array(
|
||||
'join_tags' =>
|
||||
array(
|
||||
'join' => 'LEFT JOIN '.$table
|
||||
.' ON idf_upload_id=id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function __toString()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
function _toIndex()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
function preSave($create=false)
|
||||
{
|
||||
if ($this->id == '') {
|
||||
$this->creation_dtime = gmdate('Y-m-d H:i:s');
|
||||
$this->modif_dtime = gmdate('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
|
||||
function getAbsoluteUrl($project)
|
||||
{
|
||||
return Pluf::f('url_media').'/upload/'.$project->shortname.'/files/'.$this->file;
|
||||
}
|
||||
}
|
@@ -163,4 +163,20 @@ class IDF_Views
|
||||
'form' => $form),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* FAQ.
|
||||
*/
|
||||
public function faq($request, $match)
|
||||
{
|
||||
$title = __('Here to Help You!');
|
||||
$projects = Pluf::factory('IDF_Project')->getList();
|
||||
return Pluf_Shortcuts_RenderToResponse('faq.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'projects' => $projects,
|
||||
),
|
||||
$request);
|
||||
|
||||
}
|
||||
}
|
318
src/IDF/Views/Download.php
Normal file
@@ -0,0 +1,318 @@
|
||||
<?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 ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
Pluf::loadFunction('Pluf_Shortcuts_RenderToResponse');
|
||||
Pluf::loadFunction('Pluf_Shortcuts_GetObjectOr404');
|
||||
Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
|
||||
|
||||
/**
|
||||
* Download's views.
|
||||
*
|
||||
* - List all the files.
|
||||
* - Upload a file.
|
||||
* - See the details of a file.
|
||||
*/
|
||||
class IDF_Views_Download
|
||||
{
|
||||
/**
|
||||
* List the files available for download.
|
||||
*/
|
||||
public $index_precond = array('IDF_Precondition::accessDownloads');
|
||||
public function index($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$title = sprintf(__('%s Downloads'), (string) $prj);
|
||||
// Paginator to paginate the files to download.
|
||||
$pag = new Pluf_Paginator(new IDF_Upload());
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname);
|
||||
$pag->summary = __('This table shows the files to download.');
|
||||
$pag->action = array('IDF_Views_Download::index', array($prj->shortname));
|
||||
$pag->edit_action = array('IDF_Views_Download::view', 'shortname', 'id');
|
||||
$pag->forced_where = new Pluf_SQL('project=%s', array($prj->id));
|
||||
$list_display = array(
|
||||
'file' => __('File'),
|
||||
array('summary', 'IDF_Views_Download_SummaryAndLabels', __('Summary')),
|
||||
array('filesize', 'IDF_Views_Download_Size', __('Size')),
|
||||
array('creation_dtime', 'Pluf_Paginator_DateYMD', __('Uploaded')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('file', 'filesize', 'creation_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No downloads were found.');
|
||||
$pag->sort_order = array('creation_dtime', 'DESC');
|
||||
$pag->setFromRequest($request);
|
||||
$tags = $prj->getTagCloud('downloads');
|
||||
return Pluf_Shortcuts_RenderToResponse('downloads/index.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'downloads' => $pag,
|
||||
'tags' => $tags,
|
||||
),
|
||||
$request);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* View details of a file.
|
||||
*/
|
||||
public $view_precond = array('IDF_Precondition::accessDownloads');
|
||||
public function view($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$upload = Pluf_Shortcuts_GetObjectOr404('IDF_Upload', $match[2]);
|
||||
$prj->inOr404($upload);
|
||||
$title = sprintf(__('Download %s'), $upload->summary);
|
||||
$form = false;
|
||||
$ptags = self::getDownloadTags($prj);
|
||||
$dtag = array_pop($ptags); // The last tag is the deprecated tag.
|
||||
$tags = $upload->get_tags_list();
|
||||
$deprecated = Pluf_Model_InArray($dtag, $tags);
|
||||
if ($request->method == 'POST' and
|
||||
true === IDF_Precondition::projectMemberOrOwner($request)) {
|
||||
|
||||
$form = new IDF_Form_UpdateUpload($request->POST,
|
||||
array('project' => $prj,
|
||||
'upload' => $upload,
|
||||
'user' => $request->user));
|
||||
if ($form->isValid()) {
|
||||
$upload = $form->save();
|
||||
$urlfile = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
|
||||
array($prj->shortname, $upload->id));
|
||||
$request->user->setMessage(sprintf(__('The file <a href="%1$s">%2$s</a> has been updated.'), $urlfile, Pluf_esc($upload->file)));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::index',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} elseif (true === IDF_Precondition::projectMemberOrOwner($request)) {
|
||||
$form = new IDF_Form_UpdateUpload(null,
|
||||
array('upload' => $upload,
|
||||
'project' => $prj,
|
||||
'user' => $request->user));
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('downloads/view.html',
|
||||
array(
|
||||
'file' => $upload,
|
||||
'deprecated' => $deprecated,
|
||||
'tags' => $tags,
|
||||
'auto_labels' => self::autoCompleteArrays($prj),
|
||||
'page_title' => $title,
|
||||
'form' => $form,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file.
|
||||
*/
|
||||
public $delete_precond = array('IDF_Precondition::accessDownloads',
|
||||
'IDF_Precondition::projectMemberOrOwner');
|
||||
public function delete($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$upload = Pluf_Shortcuts_GetObjectOr404('IDF_Upload', $match[2]);
|
||||
$prj->inOr404($upload);
|
||||
$title = sprintf(__('Delete Download %s'), $upload->summary);
|
||||
$form = false;
|
||||
$ptags = self::getDownloadTags($prj);
|
||||
$dtag = array_pop($ptags); // The last tag is the deprecated tag.
|
||||
$tags = $upload->get_tags_list();
|
||||
$deprecated = Pluf_Model_InArray($dtag, $tags);
|
||||
if ($request->method == 'POST') {
|
||||
$fname = $upload->file;
|
||||
@unlink(Pluf::f('upload_path').'/'.$prj->shortname.'/files/'.$fname);
|
||||
$upload->delete();
|
||||
$request->user->setMessage(__('The file has been deleted.'));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::index',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('downloads/delete.html',
|
||||
array(
|
||||
'file' => $upload,
|
||||
'deprecated' => $deprecated,
|
||||
'tags' => $tags,
|
||||
'page_title' => $title,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a file.
|
||||
*/
|
||||
public $download_precond = array('IDF_Precondition::accessDownloads');
|
||||
public function download($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$upload = Pluf_Shortcuts_GetObjectOr404('IDF_Upload', $match[2]);
|
||||
$prj->inOr404($upload);
|
||||
$upload->downloads += 1;
|
||||
$upload->update();
|
||||
return new Pluf_HTTP_Response_Redirect($upload->getAbsoluteUrl($prj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a new file for download.
|
||||
*/
|
||||
public $submit_precond = array('IDF_Precondition::accessDownloads',
|
||||
'IDF_Precondition::projectMemberOrOwner');
|
||||
public function submit($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$title = __('New Download');
|
||||
if ($request->method == 'POST') {
|
||||
$form = new IDF_Form_Upload(array_merge($request->POST, $request->FILES),
|
||||
array('project' => $prj,
|
||||
'user' => $request->user));
|
||||
if ($form->isValid()) {
|
||||
$upload = $form->save();
|
||||
$urlfile = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
|
||||
array($prj->shortname, $upload->id));
|
||||
$request->user->setMessage(sprintf(__('The <a href="%s">file</a> has been uploaded.'), $urlfile));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::index',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
$form = new IDF_Form_Upload(null,
|
||||
array('project' => $prj,
|
||||
'user' => $request->user));
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('downloads/submit.html',
|
||||
array(
|
||||
'auto_labels' => self::autoCompleteArrays($prj),
|
||||
'page_title' => $title,
|
||||
'form' => $form,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the autocomplete arrays for the little AJAX stuff.
|
||||
*/
|
||||
public static function autoCompleteArrays($project)
|
||||
{
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($project);
|
||||
$st = preg_split("/\015\012|\015|\012/",
|
||||
$conf->getVal('labels_downloads_predefined', IDF_Form_UploadConf::init_predefined), -1, PREG_SPLIT_NO_EMPTY);
|
||||
$auto = '';
|
||||
foreach ($st as $s) {
|
||||
$v = '';
|
||||
$d = '';
|
||||
$_s = split('=', $s, 2);
|
||||
if (count($_s) > 1) {
|
||||
$v = trim($_s[0]);
|
||||
$d = trim($_s[1]);
|
||||
} else {
|
||||
$v = trim($_s[0]);
|
||||
}
|
||||
$auto .= sprintf('{ name: "%s", to: "%s" }, ',
|
||||
Pluf_esc($d), Pluf_esc($v));
|
||||
}
|
||||
return substr($auto, 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* View list of downloads with a given label.
|
||||
*/
|
||||
public $listLabel_precond = array('IDF_Precondition::accessDownloads');
|
||||
public function listLabel($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $match[2]);
|
||||
$prj->inOr404($tag);
|
||||
$title = sprintf(__('%1$s Downloads with Label %2$s'), (string) $prj,
|
||||
(string) $tag);
|
||||
// Paginator to paginate the downloads
|
||||
$pag = new Pluf_Paginator(new IDF_Upload());
|
||||
$pag->model_view = 'join_tags';
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname);
|
||||
$pag->summary = sprintf(__('This table shows the downloads with label %s.'), (string) $tag);
|
||||
$pag->forced_where = new Pluf_SQL('project=%s AND idf_tag_id=%s', array($prj->id, $tag->id));
|
||||
$pag->action = array('IDF_Views_Download::index', array($prj->shortname));
|
||||
$pag->edit_action = array('IDF_Views_Download::view', 'shortname', 'id');
|
||||
$list_display = array(
|
||||
'file' => __('File'),
|
||||
array('summary', 'IDF_Views_Download_SummaryAndLabels', __('Summary')),
|
||||
array('filesize', 'IDF_Views_Download_Size', __('Size')),
|
||||
array('creation_dtime', 'Pluf_Paginator_DateYMD', __('Uploaded')),
|
||||
);
|
||||
$pag->configure($list_display, array(), array('file', 'filesize', 'creation_dtime'));
|
||||
$pag->items_per_page = 10;
|
||||
$pag->no_results_text = __('No downloads were found.');
|
||||
$pag->sort_order = array('creation_dtime', 'DESC');
|
||||
$pag->setFromRequest($request);
|
||||
$tags = $prj->getTagCloud('downloads');
|
||||
return Pluf_Shortcuts_RenderToResponse('downloads/index.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'label' => $tag,
|
||||
'downloads' => $pag,
|
||||
'tags' => $tags,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the download tags.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return ArrayObject The tags
|
||||
*/
|
||||
public static function getDownloadTags($project)
|
||||
{
|
||||
return $project->getTagsFromConfig('labels_downloads_predefined',
|
||||
IDF_Form_UploadConf::init_predefined);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the summary of a download, then on a new line, display the
|
||||
* list of labels.
|
||||
*
|
||||
* The summary of the download is linking to the download.
|
||||
*/
|
||||
function IDF_Views_Download_SummaryAndLabels($field, $down, $extra='')
|
||||
{
|
||||
$tags = array();
|
||||
foreach ($down->get_tags_list() as $tag) {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::listLabel',
|
||||
array($down->shortname, $tag->id));
|
||||
$tags[] = sprintf('<a href="%s" class="label">%s</a>', $url, Pluf_esc((string) $tag));
|
||||
}
|
||||
$out = '';
|
||||
if (count($tags)) {
|
||||
$out = '<br /><span class="note">'.implode(', ', $tags).'</span>';
|
||||
}
|
||||
return Pluf_esc($down->summary).$out;
|
||||
}
|
||||
|
||||
function IDF_Views_Download_Size($field, $down)
|
||||
{
|
||||
return Pluf_Utils::prettySize($down->$field);
|
||||
}
|
@@ -34,10 +34,11 @@ class IDF_Views_Issue
|
||||
/**
|
||||
* View list of issues for a given project.
|
||||
*/
|
||||
public $index_precond = array('IDF_Precondition::accessIssues');
|
||||
public function index($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$title = sprintf(__('%s Recent Issues'), (string) $prj);
|
||||
$title = sprintf(__('%s Open Issues'), (string) $prj);
|
||||
// Get stats about the issues
|
||||
$open = $prj->getIssueCountByStatus('open');
|
||||
$closed = $prj->getIssueCountByStatus('closed');
|
||||
@@ -45,13 +46,15 @@ class IDF_Views_Issue
|
||||
$pag = new Pluf_Paginator(new IDF_Issue());
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname);
|
||||
$pag->summary = __('This table shows the open recent issues.');
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user);
|
||||
$pag->summary = __('This table shows the open issues.');
|
||||
$otags = $prj->getTagIdsByStatus('open');
|
||||
if (count($otags) == 0) $otags[] = 0;
|
||||
$pag->forced_where = new Pluf_SQL('project=%s AND status IN ('.implode(', ', $otags).')', array($prj->id));
|
||||
$pag->action = array('IDF_Views_Issue::index', array($prj->shortname));
|
||||
$pag->sort_order = array('modif_dtime', 'DESC');
|
||||
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
||||
$pag->sort_reverse_order = array('modif_dtime');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
@@ -68,6 +71,7 @@ class IDF_Views_Issue
|
||||
'open' => $open,
|
||||
'closed' => $closed,
|
||||
'issues' => $pag,
|
||||
'cloud' => 'issues',
|
||||
),
|
||||
$request);
|
||||
}
|
||||
@@ -77,7 +81,8 @@ class IDF_Views_Issue
|
||||
*
|
||||
* Only open issues are shown.
|
||||
*/
|
||||
public $myIssues_precond = array('Pluf_Precondition::loginRequired');
|
||||
public $myIssues_precond = array('IDF_Precondition::accessIssues',
|
||||
'Pluf_Precondition::loginRequired');
|
||||
public function myIssues($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
@@ -99,11 +104,13 @@ class IDF_Views_Issue
|
||||
$pag = new Pluf_Paginator(new IDF_Issue());
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname);
|
||||
$pag->summary = __('This table shows the open recent issues.');
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user);
|
||||
$pag->summary = __('This table shows the open issues.');
|
||||
$pag->forced_where = $f_sql;
|
||||
$pag->action = array('IDF_Views_Issue::myIssues', array($prj->shortname, $match[2]));
|
||||
$pag->sort_order = array('modif_dtime', 'DESC');
|
||||
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
||||
$pag->sort_reverse_order = array('modif_dtime');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
@@ -124,7 +131,8 @@ class IDF_Views_Issue
|
||||
$request);
|
||||
}
|
||||
|
||||
public $create_precond = array('Pluf_Precondition::loginRequired');
|
||||
public $create_precond = array('IDF_Precondition::accessIssues',
|
||||
'Pluf_Precondition::loginRequired');
|
||||
public function create($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
@@ -141,6 +149,24 @@ class IDF_Views_Issue
|
||||
$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));
|
||||
if (null != $issue->get_owner() and $issue->owner != $issue->submitter) {
|
||||
$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'),
|
||||
)
|
||||
);
|
||||
$oemail = $issue->get_owner()->email;
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $oemail,
|
||||
sprintf(__('Issue %s - %s (InDefero)'),
|
||||
$issue->id, $issue->summary));
|
||||
$tmpl = new Pluf_Template('issues/issue-created-email.txt');
|
||||
$email->addTextMessage($tmpl->render($context));
|
||||
$email->sendMail();
|
||||
}
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
@@ -157,19 +183,63 @@ class IDF_Views_Issue
|
||||
$request);
|
||||
}
|
||||
|
||||
public $search_precond = array('IDF_Precondition::accessIssues');
|
||||
public function search($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
if (!isset($request->REQUEST['q']) or trim($request->REQUEST['q']) == '') {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$q = $request->REQUEST['q'];
|
||||
$title = sprintf(__('Search Issues - %s'), Pluf_esc($q));
|
||||
$issues = new Pluf_Search_ResultSet(IDF_Search::mySearch($q, $prj));
|
||||
if (count($issues) > 100) {
|
||||
// no more than 100 results as we do not care
|
||||
$issues->results = array_slice($issues->results, 0, 100);
|
||||
}
|
||||
$pag = new Pluf_Paginator();
|
||||
$pag->items = $issues;
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user);
|
||||
$pag->summary = __('This table shows the found issues.');
|
||||
$pag->action = array('IDF_Views_Issue::search', array($prj->shortname), array('q'=> $q));
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
|
||||
array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
|
||||
);
|
||||
$pag->configure($list_display);
|
||||
$pag->items_per_page = 100;
|
||||
$pag->no_results_text = __('No issues were found.');
|
||||
$pag->setFromRequest($request);
|
||||
$params = array('page_title' => $title,
|
||||
'issues' => $pag,
|
||||
'q' => $q,
|
||||
);
|
||||
return Pluf_Shortcuts_RenderToResponse('issues/search.html', $params, $request);
|
||||
|
||||
}
|
||||
|
||||
public $view_precond = array('IDF_Precondition::accessIssues');
|
||||
public function view($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$issue = Pluf_Shortcuts_GetObjectOr404('IDF_Issue', $match[2]);
|
||||
if ($issue->project != $prj->id) {
|
||||
throw new Pluf_HTTP_Error404();
|
||||
}
|
||||
$prj->inOr404($issue);
|
||||
$comments = $issue->get_comments_list(array('order' => 'id ASC'));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||
array($prj->shortname, $issue->id));
|
||||
$title = Pluf_Template::markSafe(sprintf(__('Issue <a href="%s">%d</a>: %s'), $url, $issue->id, $issue->summary));
|
||||
$form = false; // The form is available only if logged in.
|
||||
$starred = false;
|
||||
$closed = in_array($issue->status, $prj->getTagIdsByStatus('closed'));
|
||||
if (!$request->user->isAnonymous()) {
|
||||
$starred = Pluf_Model_InArray($request->user, $issue->get_interested_list());
|
||||
$params = array(
|
||||
'project' => $prj,
|
||||
'user' => $request->user,
|
||||
@@ -184,6 +254,38 @@ class IDF_Views_Issue
|
||||
$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
|
||||
$interested = $issue->get_interested_list();
|
||||
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();
|
||||
}
|
||||
$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('issues/issue-updated-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail_Batch(Pluf::f('from_email'));
|
||||
foreach ($interested as $user) {
|
||||
if ($user->id != $request->user->id) {
|
||||
$email->setSubject(sprintf(__('Updated Issue %s - %s (InDefero)'),
|
||||
$issue->id, $issue->summary));
|
||||
$email->setTo($user->email);
|
||||
$email->setReturnPath(Pluf::f('from_email'));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
}
|
||||
}
|
||||
$email->close();
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
@@ -193,11 +295,13 @@ class IDF_Views_Issue
|
||||
$arrays = self::autoCompleteArrays($prj);
|
||||
return Pluf_Shortcuts_RenderToResponse('issues/view.html',
|
||||
array_merge(
|
||||
array('project' => $prj,
|
||||
array(
|
||||
'issue' => $issue,
|
||||
'comments' => $comments,
|
||||
'form' => $form,
|
||||
'starred' => $starred,
|
||||
'page_title' => $title,
|
||||
'closed' => $closed,
|
||||
),
|
||||
$arrays),
|
||||
$request);
|
||||
@@ -206,6 +310,7 @@ class IDF_Views_Issue
|
||||
/**
|
||||
* View list of issues for a given project with a given status.
|
||||
*/
|
||||
public $listStatus_precond = array('IDF_Precondition::accessIssues');
|
||||
public function listStatus($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
@@ -218,13 +323,15 @@ class IDF_Views_Issue
|
||||
$pag = new Pluf_Paginator(new IDF_Issue());
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname);
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user);
|
||||
$pag->summary = __('This table shows the closed issues.');
|
||||
$otags = $prj->getTagIdsByStatus('closed');
|
||||
if (count($otags) == 0) $otags[] = 0;
|
||||
$pag->forced_where = new Pluf_SQL('project=%s AND status IN ('.implode(', ', $otags).')', array($prj->id));
|
||||
$pag->action = array('IDF_Views_Issue::index', array($prj->shortname));
|
||||
$pag->sort_order = array('modif_dtime', 'DESC');
|
||||
$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');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
@@ -241,6 +348,7 @@ class IDF_Views_Issue
|
||||
'open' => $open,
|
||||
'closed' => $closed,
|
||||
'issues' => $pag,
|
||||
'cloud' => 'closed_issues',
|
||||
),
|
||||
$request);
|
||||
}
|
||||
@@ -248,6 +356,7 @@ class IDF_Views_Issue
|
||||
/**
|
||||
* View list of issues for a given project with a given label.
|
||||
*/
|
||||
public $listLabel_precond = array('IDF_Precondition::accessIssues');
|
||||
public function listLabel($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
@@ -271,13 +380,15 @@ class IDF_Views_Issue
|
||||
$pag->model_view = 'join_tags';
|
||||
$pag->class = 'recent-issues';
|
||||
$pag->item_extra_props = array('project_m' => $prj,
|
||||
'shortname' => $prj->shortname);
|
||||
'shortname' => $prj->shortname,
|
||||
'current_user' => $request->user);
|
||||
$pag->summary = sprintf(__('This table shows the issues with label %s.'), (string) $tag);
|
||||
$otags = $prj->getTagIdsByStatus($status);
|
||||
if (count($otags) == 0) $otags[] = 0;
|
||||
$pag->forced_where = new Pluf_SQL('project=%s AND idf_tag_id=%s AND status IN ('.implode(', ', $otags).')', array($prj->id, $tag->id));
|
||||
$pag->action = array('IDF_Views_Issue::listLabel', array($prj->shortname, $tag->id, $status));
|
||||
$pag->sort_order = array('modif_dtime', 'DESC');
|
||||
$pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted
|
||||
$pag->sort_reverse_order = array('modif_dtime');
|
||||
$list_display = array(
|
||||
'id' => __('Id'),
|
||||
array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
|
||||
@@ -305,6 +416,31 @@ class IDF_Views_Issue
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Star/Unstar an issue.
|
||||
*/
|
||||
public $star_precond = array('IDF_Precondition::accessIssues',
|
||||
'Pluf_Precondition::loginRequired');
|
||||
public function star($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$issue = Pluf_Shortcuts_GetObjectOr404('IDF_Issue', $match[2]);
|
||||
$prj->inOr404($issue);
|
||||
if ($request->method == 'POST') {
|
||||
$starred = Pluf_Model_InArray($request->user, $issue->get_interested_list());
|
||||
if ($starred) {
|
||||
$issue->delAssoc($request->user);
|
||||
$request->user->setMessage(__('The issue has been removed from your watch list.'));
|
||||
} else {
|
||||
$issue->setAssoc($request->user);
|
||||
$request->user->setMessage(__('The issue has been added to your watch list.'));
|
||||
}
|
||||
}
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||
array($prj->shortname, $issue->id));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the autocomplete arrays for the little AJAX stuff.
|
||||
*/
|
||||
@@ -372,11 +508,16 @@ function IDF_Views_Issue_SummaryAndLabels($field, $issue, $extra='')
|
||||
array($issue->shortname, $tag->id, 'open'));
|
||||
$tags[] = sprintf('<a class="label" href="%s">%s</a>', $url, Pluf_esc((string) $tag));
|
||||
}
|
||||
$s = '';
|
||||
if (!$issue->current_user->isAnonymous() and
|
||||
Pluf_Model_InArray($issue->current_user, $issue->get_interested_list())) {
|
||||
$s = '<img style="vertical-align: text-bottom;" src="'.Pluf_Template_Tag_MediaUrl::url('/idf/img/star.png').'" alt="'.__('On your watch list.').'" /> ';
|
||||
}
|
||||
$out = '';
|
||||
if (count($tags)) {
|
||||
$out = '<br /><span class="note">'.implode(', ', $tags).'</span>';
|
||||
}
|
||||
return sprintf('<a href="%s">%s</a>', $edit, Pluf_esc($issue->summary)).$out;
|
||||
return $s.sprintf('<a href="%s">%s</a>', $edit, Pluf_esc($issue->summary)).$out;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -39,10 +39,17 @@ class IDF_Views_Project
|
||||
$prj = $request->project;
|
||||
$team = $prj->getMembershipData();
|
||||
$title = (string) $prj;
|
||||
$downloads = array();
|
||||
if ($request->rights['hasDownloadsAccess']) {
|
||||
$tags = IDF_Views_Download::getDownloadTags($prj);
|
||||
// the first tag is the featured, the last is the deprecated.
|
||||
$downloads = $tags[0]->get_idf_upload_list();
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('project-home.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'team' => $team,
|
||||
'downloads' => $downloads,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
@@ -82,7 +89,7 @@ class IDF_Views_Project
|
||||
/**
|
||||
* Administrate the issue tracking of a project.
|
||||
*/
|
||||
public $adminIssueTracking_precond = array('IDF_Precondition::projectOwner');
|
||||
public $adminIssues_precond = array('IDF_Precondition::projectOwner');
|
||||
public function adminIssues($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
@@ -123,6 +130,49 @@ class IDF_Views_Project
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Administrate the downloads of a project.
|
||||
*/
|
||||
public $adminDownloads_precond = array('IDF_Precondition::projectOwner');
|
||||
public function adminDownloads($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$title = sprintf(__('%s Downloads Configuration'), (string) $prj);
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($prj);
|
||||
if ($request->method == 'POST') {
|
||||
$form = new IDF_Form_UploadConf($request->POST);
|
||||
if ($form->isValid()) {
|
||||
foreach ($form->cleaned_data as $key=>$val) {
|
||||
$conf->setVal($key, $val);
|
||||
}
|
||||
$request->user->setMessage(__('The downloads configuration has been saved.'));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Project::adminDownloads',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
$params = array();
|
||||
$keys = array('labels_download_predefined', 'labels_download_one_max');
|
||||
foreach ($keys as $key) {
|
||||
$_val = $conf->getVal($key, false);
|
||||
if ($_val !== false) {
|
||||
$params[$key] = $_val;
|
||||
}
|
||||
}
|
||||
if (count($params) == 0) {
|
||||
$params = null; //Nothing in the db, so new form.
|
||||
}
|
||||
$form = new IDF_Form_UploadConf($params);
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('admin/downloads.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'form' => $form,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Administrate the members of a project.
|
||||
*/
|
||||
@@ -154,4 +204,49 @@ class IDF_Views_Project
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Administrate the access rights to the tabs.
|
||||
*/
|
||||
public $adminTabs_precond = array('IDF_Precondition::projectOwner');
|
||||
public function adminTabs($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
$title = sprintf(__('%s Tabs Access Rights'), (string) $prj);
|
||||
$extra = array(
|
||||
'conf' => $request->conf,
|
||||
);
|
||||
if ($request->method == 'POST') {
|
||||
$form = new IDF_Form_TabsConf($request->POST, $extra);
|
||||
if ($form->isValid()) {
|
||||
foreach ($form->cleaned_data as $key=>$val) {
|
||||
$request->conf->setVal($key, $val);
|
||||
}
|
||||
$request->user->setMessage(__('The project tabs access rights have been saved.'));
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Project::adminTabs',
|
||||
array($prj->shortname));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
$params = array();
|
||||
$keys = array('downloads_access_rights', 'source_access_rights',
|
||||
'issues_access_rights');
|
||||
foreach ($keys as $key) {
|
||||
$_val = $request->conf->getVal($key, false);
|
||||
if ($_val !== false) {
|
||||
$params[$key] = $_val;
|
||||
}
|
||||
}
|
||||
if (count($params) == 0) {
|
||||
$params = null; //Nothing in the db, so new form.
|
||||
}
|
||||
$form = new IDF_Form_TabsConf($params, $extra);
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('admin/tabs.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'form' => $form,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
}
|
@@ -31,13 +31,16 @@ Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
|
||||
*/
|
||||
class IDF_Views_Source
|
||||
{
|
||||
public $changeLog_precond = array('IDF_Precondition::accessSource');
|
||||
public function changeLog($request, $match)
|
||||
{
|
||||
$title = sprintf('%s Git Change Log', (string) $request->project);
|
||||
$git = new IDF_Git(Pluf::f('git_repository'));
|
||||
$branches = $git->getBranches();
|
||||
$title = sprintf(__('%s %s Change Log'), (string) $request->project,
|
||||
$this->getScmType($request));
|
||||
$scm = IDF_Scm::get($request);
|
||||
$branches = $scm->getBranches();
|
||||
$commit = $match[2];
|
||||
$res = $git->getChangeLog($commit, 50);
|
||||
$res = $scm->getChangeLog($commit, 25);
|
||||
$scmConf = $request->conf->getVal('scm', 'git');
|
||||
return Pluf_Shortcuts_RenderToResponse('source/changelog.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
@@ -45,27 +48,36 @@ class IDF_Views_Source
|
||||
'changes' => $res,
|
||||
'commit' => $commit,
|
||||
'branches' => $branches,
|
||||
'scm' => $scmConf,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
public $treeBase_precond = array('IDF_Precondition::accessSource');
|
||||
public function treeBase($request, $match)
|
||||
{
|
||||
$title = sprintf('%s Git Source Tree', (string) $request->project);
|
||||
$git = new IDF_Git(Pluf::f('git_repository'));
|
||||
$title = sprintf(__('%s %s Source Tree'), (string) $request->project,
|
||||
$this->getScmType($request));
|
||||
$scm = IDF_Scm::get($request);
|
||||
$commit = $match[2];
|
||||
$branches = $git->getBranches();
|
||||
if ('commit' != $git->testHash($commit)) {
|
||||
$branches = $scm->getBranches();
|
||||
if ('commit' != $scm->testHash($commit)) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$res = $git->filesAtCommit($commit);
|
||||
$cobject = $git->getCommit($commit);
|
||||
|
||||
$res = $scm->filesAtCommit($commit);
|
||||
$cobject = $scm->getCommit($commit);
|
||||
$tree_in = in_array($commit, $branches);
|
||||
return Pluf_Shortcuts_RenderToResponse('source/tree.html',
|
||||
$scmConf = $request->conf->getVal('scm', 'git');
|
||||
$props = null;
|
||||
if ($scmConf === 'svn') {
|
||||
$props = $scm->getProperties($commit);
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('source/'.$scmConf.'/tree.html',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'title' => $title,
|
||||
@@ -74,25 +86,28 @@ class IDF_Views_Source
|
||||
'commit' => $commit,
|
||||
'tree_in' => $tree_in,
|
||||
'branches' => $branches,
|
||||
'props' => $props,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
public $tree_precond = array('IDF_Precondition::accessSource');
|
||||
public function tree($request, $match)
|
||||
{
|
||||
$title = sprintf('%s Git Source Tree', (string) $request->project);
|
||||
$git = new IDF_Git(Pluf::f('git_repository'));
|
||||
$branches = $git->getBranches();
|
||||
$title = sprintf(__('%s %s Source Tree'), (string) $request->project,
|
||||
$this->getScmType($request));
|
||||
$scm = IDF_Scm::get($request);
|
||||
$branches = $scm->getBranches();
|
||||
$commit = $match[2];
|
||||
if ('commit' != $git->testHash($commit)) {
|
||||
$request_file = $match[3];
|
||||
if ('commit' != $scm->testHash($commit, $request_file)) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$request_file = $match[3];
|
||||
$request_file_info = $git->getFileInfo($request_file, $commit);
|
||||
$request_file_info = $scm->getFileInfo($request_file, $commit);
|
||||
if (!$request_file_info) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
@@ -101,19 +116,33 @@ class IDF_Views_Source
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
if ($request_file_info->type != 'tree') {
|
||||
return new Pluf_HTTP_Response($git->getBlob($request_file_info->hash),
|
||||
'application/octet-stream');
|
||||
$info = self::getMimeType($request_file_info->file);
|
||||
if (Pluf::f('src') == 'git') {
|
||||
$rep = new Pluf_HTTP_Response($scm->getBlob($request_file_info->hash),
|
||||
$info[0]);
|
||||
}
|
||||
else {
|
||||
$rep = new Pluf_HTTP_Response($scm->getBlob($request_file_info->fullpath, $commit),
|
||||
$info[0]);
|
||||
}
|
||||
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$info[1].'"';
|
||||
return $rep;
|
||||
}
|
||||
$bc = self::makeBreadCrumb($request->project, $commit, $request_file_info->file);
|
||||
$page_title = $bc.' - '.$title;
|
||||
$cobject = $git->getCommit($commit);
|
||||
$cobject = $scm->getCommit($commit);
|
||||
$tree_in = in_array($commit, $branches);
|
||||
$res = $git->filesAtCommit($commit, $request_file);
|
||||
$res = $scm->filesAtCommit($commit, $request_file);
|
||||
// try to find the previous level if it exists.
|
||||
$prev = split('/', $request_file);
|
||||
$l = array_pop($prev);
|
||||
$previous = substr($request_file, 0, -strlen($l.' '));
|
||||
return Pluf_Shortcuts_RenderToResponse('source/tree.html',
|
||||
$scmConf = $request->conf->getVal('scm', 'git');
|
||||
$props = null;
|
||||
if ($scmConf === 'svn') {
|
||||
$props = $scm->getProperties($commit, $request_file);
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('source/'.$scmConf.'/tree.html',
|
||||
array(
|
||||
'page_title' => $page_title,
|
||||
'title' => $title,
|
||||
@@ -125,6 +154,7 @@ class IDF_Views_Source
|
||||
'prev' => $previous,
|
||||
'tree_in' => $tree_in,
|
||||
'branches' => $branches,
|
||||
'props' => $props,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
@@ -146,24 +176,25 @@ class IDF_Views_Source
|
||||
return '<span class="breadcrumb">'.implode('<span class="sep">'.$sep.'</span>', $out).'</span>';
|
||||
}
|
||||
|
||||
public $commit_precond = array('IDF_Precondition::accessSource');
|
||||
public function commit($request, $match)
|
||||
{
|
||||
|
||||
$git = new IDF_Git(Pluf::f('git_repository'));
|
||||
$scm = IDF_Scm::get($request);
|
||||
$commit = $match[2];
|
||||
$branches = $git->getBranches();
|
||||
if ('commit' != $git->testHash($commit)) {
|
||||
$branches = $scm->getBranches();
|
||||
if ('commit' != $scm->testHash($commit)) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
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);
|
||||
$cobject = $git->getCommit($commit);
|
||||
$title = sprintf(__('%s Commit Details'), (string) $request->project);
|
||||
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
|
||||
$cobject = $scm->getCommit($commit);
|
||||
$diff = new IDF_Diff($cobject->changes);
|
||||
$diff->parse();
|
||||
$scmConf = $request->conf->getVal('scm', 'git');
|
||||
return Pluf_Shortcuts_RenderToResponse('source/commit.html',
|
||||
array(
|
||||
'page_title' => $page_title,
|
||||
@@ -172,11 +203,141 @@ class IDF_Views_Source
|
||||
'cobject' => $cobject,
|
||||
'commit' => $commit,
|
||||
'branches' => $branches,
|
||||
'scm' => $scmConf,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a zip archive of the current commit.
|
||||
*
|
||||
*/
|
||||
public $download_precond = array('IDF_Precondition::accessSource');
|
||||
public function download($request, $match)
|
||||
{
|
||||
$commit = trim($match[2]);
|
||||
$scm = IDF_Scm::get($request);
|
||||
$branches = $scm->getBranches();
|
||||
if ('commit' != $scm->testHash($commit)) {
|
||||
// Redirect to the first branch
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($request->project->shortname,
|
||||
$branches[0]));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
$base = $request->project->shortname.'-'.$commit;
|
||||
$cmd = $scm->getArchiveCommand($commit, $base.'/');
|
||||
$rep = new Pluf_HTTP_Response_CommandPassThru($cmd, 'application/x-zip');
|
||||
$rep->headers['Content-Transfer-Encoding'] = 'binary';
|
||||
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$base.'.zip"';
|
||||
return $rep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display tree of a specific SVN revision
|
||||
*
|
||||
*/
|
||||
public function treeRev($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
|
||||
// Redirect to tree base if not svn
|
||||
if ($request->conf->getVal('scm', 'git') != 'svn') {
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($prj->shortname, $prj->getScmRoot()));
|
||||
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
|
||||
// Get revision value
|
||||
if (!isset($request->REQUEST['rev']) or trim($request->REQUEST['rev']) == '') {
|
||||
$scmRoot = $prj->getScmRoot();
|
||||
}
|
||||
else {
|
||||
$scmRoot = $request->REQUEST['rev'];
|
||||
}
|
||||
|
||||
// Get source if not /
|
||||
if (isset($request->REQUEST['sourcefile']) and trim($request->REQUEST['sourcefile']) != '') {
|
||||
$scmRoot .= '/'.$request->REQUEST['sourcefile'];
|
||||
}
|
||||
|
||||
// Redirect
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
|
||||
array($prj->shortname, $scmRoot));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display SVN changelog from specific revision
|
||||
*
|
||||
*/
|
||||
public function changelogRev($request, $match)
|
||||
{
|
||||
$prj = $request->project;
|
||||
|
||||
// Redirect to tree base if not svn
|
||||
if ($request->conf->getVal('scm', 'git') != 'svn') {
|
||||
$scmRoot = $prj->getScmRoot();
|
||||
}
|
||||
// Get revision value if svn
|
||||
else {
|
||||
if (!isset($request->REQUEST['rev']) or trim($request->REQUEST['rev']) == '') {
|
||||
$scmRoot = $prj->getScmRoot();
|
||||
}
|
||||
else {
|
||||
$scmRoot = $request->REQUEST['rev'];
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect
|
||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::changeLog',
|
||||
array($prj->shortname, $scmRoot));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the mime type of a file.
|
||||
*
|
||||
* Use /etc/mime.types to find the type.
|
||||
*
|
||||
* @param string Filename/Filepath
|
||||
* @param string Path to the mime types database ('/etc/mime.types')
|
||||
* @param array Mime type found or 'application/octet-stream' and basename
|
||||
*/
|
||||
public static function getMimeType($file, $src='/etc/mime.types')
|
||||
{
|
||||
$mimes = preg_split("/\015\012|\015|\012/", file_get_contents($src));
|
||||
$info = pathinfo($file);
|
||||
if (isset($info['extension'])) {
|
||||
foreach ($mimes as $mime) {
|
||||
if ('#' != substr($mime, 0, 1)) {
|
||||
$elts = preg_split('/ |\t/', $mime, -1, PREG_SPLIT_NO_EMPTY);
|
||||
if (in_array($info['extension'], $elts)) {
|
||||
return array($elts[0], $info['basename']);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we consider that if no extension and base name is all
|
||||
// uppercase, then we have a text file.
|
||||
if ($info['basename'] == strtoupper($info['basename'])) {
|
||||
return array('text/plain', $info['basename']);
|
||||
}
|
||||
}
|
||||
return array('application/octet-stream', $info['basename']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scm type for page title
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
private function getScmType($request)
|
||||
{
|
||||
return mb_convert_case($request->conf->getVal('scm', 'git'),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
}
|
||||
|
||||
function IDF_Views_Source_PrettySize($size)
|
||||
|
78
src/IDF/Views/User.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?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 ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
Pluf::loadFunction('Pluf_Shortcuts_RenderToResponse');
|
||||
|
||||
/**
|
||||
* User management views.
|
||||
*
|
||||
* Edit your account.
|
||||
* Add emails for the link between a commit and an account.
|
||||
*/
|
||||
class IDF_Views_User
|
||||
{
|
||||
/**
|
||||
* Simple management of the base info of the user.
|
||||
*/
|
||||
public $myAccount_precond = array('Pluf_Precondition::loginRequired');
|
||||
public function myAccount($request, $match)
|
||||
{
|
||||
$params = array('user' => $request->user);
|
||||
if ($request->method == 'POST') {
|
||||
$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.'));
|
||||
return new Pluf_HTTP_Response_Redirect($url);
|
||||
}
|
||||
} else {
|
||||
$form = new IDF_Form_UserAccount($request->user->getData(), $params);
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('user/myaccount.html',
|
||||
array('page_title' => __('Your Account'),
|
||||
'form' => $form),
|
||||
$request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public profile of a user.
|
||||
*/
|
||||
public function view($request, $match)
|
||||
{
|
||||
$projects = Pluf::factory('IDF_Project')->getList();
|
||||
$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) {
|
||||
throw new Pluf_HTTP_Error404();
|
||||
}
|
||||
return Pluf_Shortcuts_RenderToResponse('user/public.html',
|
||||
array('page_title' => (string) $users[0],
|
||||
'member' => $users[0],
|
||||
'projects' => $projects,
|
||||
),
|
||||
$request);
|
||||
}
|
||||
|
||||
}
|
134
src/IDF/conf/idf.php-dist
Normal file
@@ -0,0 +1,134 @@
|
||||
<?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 ***** */
|
||||
|
||||
$cfg = array();
|
||||
|
||||
// to start with, it can be practical.
|
||||
$cfg['debug'] = false;
|
||||
|
||||
// available languages
|
||||
$cfg['languages'] = array('en', 'fr');
|
||||
|
||||
# SCM base configuration
|
||||
$cfg['allowed_scm'] = array('git' => 'IDF_Scm_Git',
|
||||
'svn' => 'IDF_Scm_Svn',
|
||||
);
|
||||
|
||||
// if you have a single git repository, just put the full path to it
|
||||
// without trailing slash.
|
||||
// If within a folder you have a series of git repository, just put
|
||||
// the folder without a trailing slash.
|
||||
// InDefero will automatically append a slash, the project shortname
|
||||
// and .git to create the name of the repository.
|
||||
$cfg['git_repositories'] = '/home/git/repositories/indefero.git';
|
||||
$cfg['git_repositories_unique'] = true;
|
||||
$cfg['git_remote_url'] = 'git://projects.ceondo.com/indefero.git';
|
||||
|
||||
// One git repository per project. "/".$project->shortname.".git"
|
||||
// is automatically added to the end of the path/url.
|
||||
//$cfg['git_repositories'] = '/home/git/repositories';
|
||||
//$cfg['git_repositories_unique'] = false;
|
||||
//$cfg['git_remote_url'] = 'git://projects.ceondo.com';
|
||||
|
||||
// Same as for git, you can have multiple repositories, one for each
|
||||
// project or a single one for all the projects.
|
||||
$cfg['svn_repositories'] = 'file:///home/svn/repositories/indefero';
|
||||
$cfg['svn_repositories_unique'] = true;
|
||||
$cfg['svn_remote_url'] = 'http://projects.ceondo.com/svn/indefero';
|
||||
|
||||
|
||||
// admins will get an email in case of errors in the system in non
|
||||
// debug mode.
|
||||
$cfg['admins'] = array(
|
||||
array('Admin', 'you@example.com'),
|
||||
);
|
||||
|
||||
// Email configuration
|
||||
$cfg['send_emails'] = true;
|
||||
$cfg['mail_backend'] = 'smtp';
|
||||
$cfg['mail_host'] = 'localhost';
|
||||
$cfg['mail_port'] = 25;
|
||||
$cfg['pear_path'] = '/usr/share/php';
|
||||
|
||||
// Paths/Url configuration
|
||||
$cfg['idf_base'] = ''; // put '/whatever/index.php if you are not
|
||||
// using mod_rewrite and installing in a
|
||||
// subfolder.
|
||||
$cfg['url_base'] = 'http://projects.ceondo.com';
|
||||
$cfg['url_media'] = 'http://projects.ceondo.com/media';
|
||||
$cfg['url_upload'] = 'http://projects/ceondo.com/media/upload';
|
||||
$cfg['upload_path'] = '/path/to/media/upload';
|
||||
|
||||
$cfg['login_success_url'] = '/';
|
||||
$cfg['after_logout_page'] = '/';
|
||||
|
||||
// write here a long random string unique for this installation. This
|
||||
// is critical to put a long string.
|
||||
$cfg['secret_key'] = '';
|
||||
|
||||
// the sender of all the emails.
|
||||
$cfg['from_email'] = 'sender@example.com';
|
||||
|
||||
// Email address for the bounced messages.
|
||||
$cfg['bounce_email'] = 'no-reply@example.com';
|
||||
|
||||
// Temporary folder where the script is writing the compiled templates,
|
||||
// cached data and other temporary resources.
|
||||
// It must be writeable by your webserver instance.
|
||||
// It is mandatory if you are using the template system.
|
||||
$cfg['tmp_folder'] = '/tmp';
|
||||
|
||||
// The folder in which the templates of the application are located.
|
||||
$cfg['template_folders'] = array(
|
||||
dirname(__FILE__).'/../templates',
|
||||
);
|
||||
|
||||
// Database configuration
|
||||
// For testing we are using in memory SQLite database.
|
||||
$cfg['db_login'] = 'www';
|
||||
$cfg['db_password'] = '';
|
||||
$cfg['db_server'] = '';
|
||||
$cfg['db_version'] = '';
|
||||
$cfg['db_table_prefix'] = '';
|
||||
$cfg['db_engine'] = 'PostgreSQL'; // SQLite is also well tested or MySQL
|
||||
$cfg['db_database'] = 'website';
|
||||
|
||||
// From this point you should not need to update anything.
|
||||
$cfg['installed_apps'] = array('Pluf', 'IDF');
|
||||
$cfg['pluf_use_rowpermission'] = true;
|
||||
$cfg['middleware_classes'] = array(
|
||||
'Pluf_Middleware_Session',
|
||||
'IDF_Middleware',
|
||||
'Pluf_Middleware_Translation',
|
||||
);
|
||||
$cfg['template_context_processors'] = array('IDF_Middleware_ContextPreProcessor');
|
||||
$cfg['idf_views'] = dirname(__FILE__).'/views.php';
|
||||
$cfg['template_tags'] = array(
|
||||
'hotkey' => 'IDF_Template_HotKey',
|
||||
'issuetext' => 'IDF_Template_IssueComment',
|
||||
);
|
||||
$cfg['template_modifiers'] = array(
|
||||
'size' => 'IDF_Views_Source_PrettySize',
|
||||
'markdown' => 'IDF_Template_Markdown_filter',
|
||||
);
|
||||
return $cfg;
|
@@ -34,7 +34,20 @@ $ctl[] = array('regex' => '#^/login/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views',
|
||||
'method' => 'login');
|
||||
'method' => 'login',
|
||||
'name' => 'login_view');
|
||||
|
||||
$ctl[] = array('regex' => '#^/preferences/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_User',
|
||||
'method' => 'myAccount');
|
||||
|
||||
$ctl[] = array('regex' => '#^/u/(.*)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_User',
|
||||
'method' => 'view');
|
||||
|
||||
$ctl[] = array('regex' => '#^/register/$#',
|
||||
'base' => $base,
|
||||
@@ -78,12 +91,24 @@ $ctl[] = array('regex' => '#^/p/(\w+)/issues/$#',
|
||||
'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,
|
||||
@@ -108,7 +133,7 @@ $ctl[] = array('regex' => '#^/p/(\w+)/issues/my/(\w+)/$#',
|
||||
'model' => 'IDF_Views_Issue',
|
||||
'method' => 'myIssues');
|
||||
|
||||
// ---------- GIT ----------------------------------------
|
||||
// ---------- SCM ----------------------------------------
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/(\w+)/source/$#',
|
||||
'base' => $base,
|
||||
@@ -140,6 +165,62 @@ $ctl[] = array('regex' => '#^/p/(\w+)/source/commit/(\w+)/$#',
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'commit');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/(\w+)/source/download/(\w+)/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'download');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/(\w+)/source/treerev/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'treeRev');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/(\w+)/source/changesrev/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Source',
|
||||
'method' => 'changelogRev');
|
||||
|
||||
// ---------- Downloads ------------------------------------
|
||||
|
||||
$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');
|
||||
|
||||
|
||||
// ---------- ADMIN --------------------------------------
|
||||
|
||||
@@ -155,10 +236,22 @@ $ctl[] = array('regex' => '#^/p/(\w+)/admin/issues/$#',
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminIssues');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/(\w+)/admin/downloads/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminDownloads');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/(\w+)/admin/members/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminMembers');
|
||||
|
||||
$ctl[] = array('regex' => '#^/p/(\w+)/admin/tabs/$#',
|
||||
'base' => $base,
|
||||
'priority' => 4,
|
||||
'model' => 'IDF_Views_Project',
|
||||
'method' => 'adminTabs');
|
||||
|
||||
return $ctl;
|
||||
|
1546
src/IDF/locale/fr/idf.po
Normal file
1483
src/IDF/locale/idf.pot
Normal file
@@ -26,5 +26,8 @@ $m['IDF_Tag'] = array('relate_to' => array('IDF_Project'));
|
||||
$m['IDF_Issue'] = array('relate_to' => array('IDF_Project', 'Pluf_User', 'IDF_Tag'),
|
||||
'relate_to_many' => array('IDF_Tag', 'Pluf_User'));
|
||||
$m['IDF_IssueComment'] = array('relate_to' => array('IDF_Issue', 'Pluf_User'));
|
||||
$m['IDF_Upload'] = array('relate_to' => array('IDF_Project', 'Pluf_User'),
|
||||
'relate_to_many' => array('IDF_Tag'));
|
||||
$m['IDF_Search_Occ'] = array('relate_to' => array('IDF_Project'),);
|
||||
|
||||
return $m;
|
||||
|
@@ -4,6 +4,8 @@
|
||||
<div id="sub-tabs">
|
||||
<a {if $inSummary}class="active" {/if}href="{url 'IDF_Views_Project::admin', array($project.shortname)}">{trans 'Project Summary'}</a> |
|
||||
<a {if $inMembers}class="active" {/if}href="{url 'IDF_Views_Project::adminMembers', array($project.shortname)}">{trans 'Project Members'}</a> |
|
||||
<a {if $inIssueTracking}class="active" {/if}href="{url 'IDF_Views_Project::adminIssues', array($project.shortname)}">{trans 'Issue Tracking'}</a>
|
||||
<a {if $inIssueTracking}class="active" {/if}href="{url 'IDF_Views_Project::adminIssues', array($project.shortname)}">{trans 'Issue Tracking'}</a> |
|
||||
<a {if $inDownloads}class="active" {/if}href="{url 'IDF_Views_Project::adminDownloads', array($project.shortname)}">{trans 'Downloads'}</a> |
|
||||
<a {if $inTabs}class="active" {/if}href="{url 'IDF_Views_Project::adminTabs', array($project.shortname)}">{trans 'Tabs Access'}</a>
|
||||
</div>
|
||||
{/block}
|
||||
|
34
src/IDF/templates/admin/downloads.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{extends "admin/base.html"}
|
||||
{block docclass}yui-t1{assign $inDownloads = true}{/block}
|
||||
{block body}
|
||||
<form method="post" action=".">
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<td colspan="2"><strong>{$form.f.labels_download_predefined.labelTag}:</strong><br />
|
||||
{if $form.f.labels_download_predefined.errors}{$form.f.labels_download_predefined.fieldErrors}{/if}
|
||||
{$form.f.labels_download_predefined|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{$form.f.labels_download_one_max.labelTag}:<br />
|
||||
{if $form.f.labels_download_one_max.errors}{$form.f.labels_download_one_max.fieldErrors}{/if}
|
||||
{$form.f.labels_download_one_max|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="submit" value="{trans 'Save Changes'}" name="submit" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{/block}
|
||||
{block context}
|
||||
<div class="issue-submit-info">
|
||||
{blocktrans}
|
||||
<p><strong>Instructions:</strong></p>
|
||||
<p>List one status value per line in desired sort-order.</p>
|
||||
<p>Optionally, use an equals-sign to document the meaning of each status value.</p>
|
||||
{/blocktrans}
|
||||
</div>
|
||||
{/block}
|
45
src/IDF/templates/admin/tabs.html
Normal file
@@ -0,0 +1,45 @@
|
||||
{extends "admin/base.html"}
|
||||
{block docclass}yui-t1{assign $inTabs = true}{/block}
|
||||
{block body}
|
||||
{if $form.errors}
|
||||
<div class="px-message-error">
|
||||
<p>{trans 'The form contains some errors. Please correct them to update the access rights.'}</p>
|
||||
{if $form.get_top_errors}
|
||||
{$form.render_top_errors|unsafe}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<form method="post" action=".">
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<th><strong>{$form.f.downloads_access_rights.labelTag}:</strong></th>
|
||||
<td>{if $form.f.downloads_access_rights.errors}{$form.f.downloads_access_rights.fieldErrors}{/if}
|
||||
{$form.f.downloads_access_rights|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.issues_access_rights.labelTag}:</strong></th>
|
||||
<td>{if $form.f.issues_access_rights.errors}{$form.f.issues_access_rights.fieldErrors}{/if}
|
||||
{$form.f.issues_access_rights|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.source_access_rights.labelTag}:</strong></th>
|
||||
<td>{if $form.f.source_access_rights.errors}{$form.f.source_access_rights.fieldErrors}{/if}
|
||||
{$form.f.source_access_rights|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="submit" value="{trans 'Save Changes'}" name="submit" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{/block}
|
||||
{block context}
|
||||
<div class="issue-submit-info">
|
||||
<p><strong>{trans 'Instructions:'}</strong></p>
|
||||
<p>{blocktrans}You can configure here the project tabs access rights.{/blocktrans}</p>
|
||||
</div>
|
||||
{/block}
|
@@ -33,15 +33,15 @@
|
||||
<body>
|
||||
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
||||
<div id="hd">
|
||||
<p class="top">
|
||||
{if !$user.isAnonymous()}{blocktrans}Welcome, <strong>{$user.first_name} {$user.last_name}</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}
|
||||
<p class="top"><a href="#title" accesskey="2"></a>
|
||||
{if !$user.isAnonymous()}{aurl 'url', 'IDF_Views_User::myAccount'}{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::faq'}">{trans 'Help'}</a>
|
||||
</p>
|
||||
{* <div id="header">
|
||||
|
||||
</div> *}
|
||||
|
||||
<h1 class="title">{block title}{$page_title}{/block}</h1>
|
||||
<h1 id="title" class="title">{block title}{$page_title}{/block}</h1>
|
||||
|
||||
</div>
|
||||
<div id="bd">
|
||||
@@ -55,7 +55,7 @@
|
||||
</div>
|
||||
<div class="yui-b context">{block context}{/block}</div>
|
||||
</div>
|
||||
<div id="ft">{block foot}{/block}</div>
|
||||
<div id="ft">{block foot}<a href="http://www.indefero.net" title="InDefero, bug tracking and more"><img src="{media '/idf/img/powered-by-indefero.png'}" alt="InDefero Logo" /></a>{/block}</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||
{block javascript}{/block}
|
||||
|
@@ -34,23 +34,24 @@
|
||||
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
||||
<div id="hd">
|
||||
{if $project}<h1 class="project-title">{$project}</h1>{/if}
|
||||
<p class="top">
|
||||
{if !$user.isAnonymous()}{blocktrans}Welcome, <strong>{$user.first_name} {$user.last_name}</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}
|
||||
<p class="top"><a href="#title" accesskey="2"></a>
|
||||
{if !$user.isAnonymous()}{aurl 'url', 'IDF_Views_User::myAccount'}{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::faq'}">{trans 'Help'}</a>
|
||||
</p>
|
||||
<div id="header">
|
||||
<div id="main-tabs">
|
||||
{if $project}
|
||||
<a href="{url 'IDF_Views_Project::home', array($project.shortname)}"{block tabhome}{/block}>{trans 'Project Home'}</a>
|
||||
<a href="{url 'IDF_Views_Issue::index', array($project.shortname)}"{block tabissues}{/block}>{trans 'Issues'}</a>
|
||||
<a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, 'master')}"{block tabsource}{/block}>{trans 'Source'}</a>
|
||||
<a accesskey="1" href="{url 'IDF_Views_Project::home', array($project.shortname)}"{block tabhome}{/block}>{trans 'Project Home'}</a>
|
||||
{if $hasIssuesAccess} <a href="{url 'IDF_Views_Issue::index', array($project.shortname)}"{block tabissues}{/block}>{trans 'Issues'}</a>{/if}
|
||||
{if $hasDownloadsAccess} <a href="{url 'IDF_Views_Download::index', array($project.shortname)}"{block tabdownloads}{/block}>{trans 'Downloads'}</a>{/if}
|
||||
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
||||
{if $isOwner}
|
||||
<a href="{url 'IDF_Views_Project::admin', array($project.shortname)}"{block tabadmin}{/block}>{trans 'Administer'}</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>
|
||||
|
||||
<h1 class="title">{block title}{$page_title}{/block}</h1>
|
||||
<h1 class="title" id="title">{block titleicon}{/block}{block title}{$page_title}{/block}</h1>
|
||||
|
||||
</div>
|
||||
<div id="bd">
|
||||
@@ -64,7 +65,7 @@
|
||||
</div>
|
||||
<div class="yui-b context">{block context}{/block}</div>
|
||||
</div>
|
||||
<div id="ft">{block foot}{/block}</div>
|
||||
<div id="ft">{block foot}<a href="http://www.indefero.net" title="InDefero, bug tracking and more"><img src="{media '/idf/img/powered-by-indefero.png'}" alt="InDefero Logo" /></a>{/block}</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||
{include 'js-hotkeys.html'}
|
||||
|
7
src/IDF/templates/downloads/base.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{extends "base.html"}
|
||||
{block tabdownloads} class="active"{/block}
|
||||
{block subtabs}
|
||||
<div id="sub-tabs">
|
||||
<a {if $inDownloads}class="active" {/if}href="{url 'IDF_Views_Download::index', array($project.shortname)}">{trans 'Downloads'}</a> {if $isOwner or $isMember}| <a {if $inSubmit}class="active" {/if}href="{url 'IDF_Views_Download::submit', array($project.shortname)}">{trans 'New Download'}</a> {/if}
|
||||
</div>
|
||||
{/block}
|
40
src/IDF/templates/downloads/delete.html
Normal file
@@ -0,0 +1,40 @@
|
||||
{extends "downloads/base.html"}
|
||||
{block docclass}yui-t3{assign $inDownloads=true}{/block}
|
||||
{block body}
|
||||
|
||||
<div class="download-file">
|
||||
<a href="{url 'IDF_Views_Download::download', array($project.shortname, $file.id)}">{$file}</a> - {$file.filesize|size}
|
||||
</div>
|
||||
|
||||
<p>{blocktrans}<strong>Attention!</strong> If you want to delete a specific version of your software, maybe, someone is depending on this specific version to run his systems. Are you sure, you will not affect anybody when removing this file?{/blocktrans}</p>
|
||||
|
||||
{if !$deprecated}{aurl 'url', 'IDF_Views_Download::view', array($project.shortname, $file.id)}
|
||||
<p>{blocktrans}Instead of deleting the file, you could <a href="{$url}">mark it as deprecated</a>.{/blocktrans}</p>{/if}
|
||||
|
||||
<form method="post" action=".">
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><input type="submit" value="{trans 'Delete File'}" name="submit" /> | <a href="{url 'IDF_Views_Download::index', array($project.shortname)}">{trans 'Cancel'}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
{/block}
|
||||
|
||||
{block context}
|
||||
{assign $submitter = $file.get_submitter()}
|
||||
<p><strong>{trans 'Uploaded:'}</strong> <span class="nobrk">{$file.creation_dtime|dateago}</span> <span class="nobrk">{blocktrans}by {$submitter}{/blocktrans}</span></p>
|
||||
{if $file.modif_dtime != $file.creation_dtime}<p>
|
||||
<strong>{trans 'Updated:'}</strong> <span class="nobrk">{$file.modif_dtime|dateago}</span></p>{/if}
|
||||
<p>
|
||||
<strong>{trans 'Downloads:'}</strong> <span class="nobrk">{$file.downloads}</span></p>
|
||||
{if $tags.count()}
|
||||
<p>
|
||||
<strong>{trans 'Labels:'}</strong><br />
|
||||
{foreach $tags as $tag}{aurl 'url', 'IDF_Views_Download::listLabel', array($project.shortname, $tag.id)}
|
||||
<span class="label"><a href="{$url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></span><br />
|
||||
{/foreach}
|
||||
</p>{/if}
|
||||
{/block}
|
19
src/IDF/templates/downloads/index.html
Normal file
@@ -0,0 +1,19 @@
|
||||
{extends "downloads/base.html"}
|
||||
{block docclass}yui-t1{assign $inDownloads=true}{/block}
|
||||
{block body}
|
||||
{$downloads.render}
|
||||
{if $isOwner or $isMember}
|
||||
{aurl 'url', 'IDF_Views_Download::submit', array($project.shortname)}
|
||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'New Download'}</a></p>{/if}
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
<p><strong>{trans 'Number of files:'}</strong> {$downloads.nb_items}</p>
|
||||
{assign $class = ''}{assign $i = 0}
|
||||
<p class="smaller">{foreach $tags as $label}
|
||||
{aurl 'url', 'IDF_Views_Download::listLabel', array($project.shortname, $label.id)}
|
||||
{if $class != $label.class}{if $i != 0}<br />{/if}<strong class="label">{$label.class}:</strong> {/if}
|
||||
<a href="{$url}" class="label">{$label.name}</a>,{assign $i = $i + 1}{assign $class = $label.class}{/foreach}</p>
|
||||
|
||||
{/block}
|
||||
|
27
src/IDF/templates/downloads/js-autocomplete.html
Normal file
@@ -0,0 +1,27 @@
|
||||
{if $isOwner or $isMember}
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery.bgiframe.min.js'}"></script>
|
||||
<script type="text/javascript" src="{media '/idf/js/jquery.autocomplete.min.js'}"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
// <!-- {literal}
|
||||
$(document).ready(function(){
|
||||
var auto_labels = [{/literal}{$auto_labels|safe}{literal}];
|
||||
var j=0;
|
||||
for (j=1;j<7;j=j+1) {
|
||||
$("#id_label"+j).autocomplete(auto_labels, {
|
||||
minChars: 0,
|
||||
width: 310,
|
||||
matchContains: true,
|
||||
max: 50,
|
||||
highlightItem: false,
|
||||
formatItem: function(row, i, max, term) {
|
||||
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
|
||||
},
|
||||
formatResult: function(row) {
|
||||
return row.to;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
{/literal} //-->
|
||||
</script>
|
||||
{/if}
|
60
src/IDF/templates/downloads/submit.html
Normal file
@@ -0,0 +1,60 @@
|
||||
{extends "downloads/base.html"}
|
||||
{block docclass}yui-t3{assign $inSubmit=true}{/block}
|
||||
{block body}
|
||||
{if $form.errors}
|
||||
<div class="px-message-error">
|
||||
<p>{trans 'The form contains some errors. Please correct them to submit the file.'}</p>
|
||||
{if $form.get_top_errors}
|
||||
{$form.render_top_errors|unsafe}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<form method="post" enctype="multipart/form-data" action=".">
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<th><strong>{$form.f.summary.labelTag}:</strong></th>
|
||||
<td>{if $form.f.summary.errors}{$form.f.summary.fieldErrors}{/if}
|
||||
{$form.f.summary|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}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$form.f.label1.labelTag}:</th>
|
||||
<td>
|
||||
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
|
||||
{if $form.f.label2.errors}{$form.f.label2.fieldErrors}{/if}{$form.f.label2|unsafe}
|
||||
{if $form.f.label3.errors}{$form.f.label3.fieldErrors}{/if}{$form.f.label3|unsafe}<br />
|
||||
{if $form.f.label4.errors}{$form.f.label4.fieldErrors}{/if}{$form.f.label4|unsafe}
|
||||
{if $form.f.label5.errors}{$form.f.label5.fieldErrors}{/if}{$form.f.label5|unsafe}
|
||||
{if $form.f.label6.errors}{$form.f.label6.fieldErrors}{/if}{$form.f.label6|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><input type="submit" value="{trans 'Submit File'}" name="submit" /> | <a href="{url 'IDF_Views_Download::index', array($project.shortname)}">{trans 'Cancel'}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{/block}
|
||||
{block context}
|
||||
<div class="issue-submit-info">
|
||||
<h2>{trans 'Instructions'}</h2>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
{/block}
|
||||
{block javascript}
|
||||
<script type="text/javascript">
|
||||
document.getElementById('id_summary').focus()
|
||||
</script>
|
||||
{include 'downloads/js-autocomplete.html'}{/block}
|
||||
|
69
src/IDF/templates/downloads/view.html
Normal file
@@ -0,0 +1,69 @@
|
||||
{extends "downloads/base.html"}
|
||||
{block docclass}yui-t3{assign $inDownloads=true}{/block}
|
||||
{block body}
|
||||
|
||||
<div class="download-file">
|
||||
{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 $form}
|
||||
{if $form.errors}
|
||||
<div class="px-message-error">
|
||||
<p>{trans 'The form contains some errors. Please correct them to update the file.'}</p>
|
||||
{if $form.get_top_errors}
|
||||
{$form.render_top_errors|unsafe}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<form method="post" enctype="multipart/form-data" action=".">
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<th><strong>{$form.f.summary.labelTag}:</strong></th>
|
||||
<td>{if $form.f.summary.errors}{$form.f.summary.fieldErrors}{/if}
|
||||
{$form.f.summary|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}
|
||||
{if $form.f.label2.errors}{$form.f.label2.fieldErrors}{/if}{$form.f.label2|unsafe}
|
||||
{if $form.f.label3.errors}{$form.f.label3.fieldErrors}{/if}{$form.f.label3|unsafe}<br />
|
||||
{if $form.f.label4.errors}{$form.f.label4.fieldErrors}{/if}{$form.f.label4|unsafe}
|
||||
{if $form.f.label5.errors}{$form.f.label5.fieldErrors}{/if}{$form.f.label5|unsafe}
|
||||
{if $form.f.label6.errors}{$form.f.label6.fieldErrors}{/if}{$form.f.label6|unsafe}
|
||||
</td>
|
||||
</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'}">Delete this file</a></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{/if}
|
||||
{/block}
|
||||
{block context}
|
||||
{assign $submitter = $file.get_submitter()}
|
||||
<p><strong>{trans 'Uploaded:'}</strong> <span class="nobrk">{$file.creation_dtime|dateago}</span> <span class="nobrk">{blocktrans}by {$submitter}{/blocktrans}</span></p>
|
||||
{if $file.modif_dtime != $file.creation_dtime}<p>
|
||||
<strong>{trans 'Updated:'}</strong> <span class="nobrk">{$file.modif_dtime|dateago}</span></p>{/if}
|
||||
<p>
|
||||
<strong>{trans 'Downloads:'}</strong> <span class="nobrk">{$file.downloads}</span></p>
|
||||
{if $tags.count()}
|
||||
<p>
|
||||
<strong>{trans 'Labels:'}</strong><br />
|
||||
{foreach $tags as $tag}{aurl 'url', 'IDF_Views_Download::listLabel', array($project.shortname, $tag.id)}
|
||||
<span class="label"><a href="{$url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></span><br />
|
||||
{/foreach}
|
||||
</p>{/if}
|
||||
{/block}
|
||||
{block javascript}{if $form}
|
||||
<script type="text/javascript">
|
||||
document.getElementById('id_summary').focus()
|
||||
</script>
|
||||
{include 'downloads/js-autocomplete.html'}{/if}{/block}
|
||||
|
47
src/IDF/templates/faq.html
Normal file
@@ -0,0 +1,47 @@
|
||||
{extends "base-simple.html"}
|
||||
{block docclass}yui-t3{/block}
|
||||
{block body}
|
||||
<ul>
|
||||
<li><a href="#q-keyboard">{trans 'What are the keyboard shortcuts?'}</a></li>
|
||||
<li><a href="#q-duplicate">{trans 'How to mark an issue as duplicate?'}</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="q-keyboard">{trans 'What are the keyboard shortcuts?'}</h2>
|
||||
|
||||
<p>{trans 'If you are in a project, you have the following shortcuts:'}</p>
|
||||
|
||||
<ul>
|
||||
<li>{trans '<kbd>Shift+h</kbd>: Project home.'}</li>
|
||||
<li>{trans '<kbd>Shift+d</kbd>: Downloads.'}</li>
|
||||
<li>{trans '<kbd>Shift+s</kbd>: Source.'}</li>
|
||||
<li>{trans '<kbd>Shift+a</kbd>: Create a new issue.'}</li>
|
||||
<li>{trans '<kbd>Shift+i</kbd>: List of open issues.'}</li>
|
||||
<li>{trans '<kbd>Shift+m</kbd>: The issues you submitted.'}</li>
|
||||
<li>{trans '<kbd>Shift+w</kbd>: The issues assigned to you.'}</li>
|
||||
</ul>
|
||||
|
||||
<p>{trans 'You also have the standard access keys:'}</p>
|
||||
|
||||
<ul>
|
||||
<li>{trans '<kbd>Alt+1</kbd>: Home.'}</li>
|
||||
<li>{trans '<kbd>Alt+2</kbd>: Skip the menus.'}</li>
|
||||
<li>{trans '<kbd>Alt+4</kbd>: Search (when available).'}</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="q-duplicate">{trans 'How to mark an issue as duplicate?'}</h2>
|
||||
|
||||
{blocktrans}<p>This is simple:</p>
|
||||
<ol>
|
||||
<li>Write in the comments "This is a duplicate of issue 123", change 123 with the corresponding issue number.</li>
|
||||
<li>Change the status of the current issue to <em>Duplicate</em>.</li>
|
||||
<li>Submit the changes.</li>
|
||||
</ol>{/blocktrans}
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
<p>{trans 'Here we are, just to help you.'}</p>
|
||||
<h2>{trans 'Projects'}</h2>
|
||||
<ul>{foreach $projects as $p}
|
||||
<li><a href="{url 'IDF_Views_Project::home', array($p.shortname)}">{$p}</a></li>
|
||||
{/foreach}</ul>
|
||||
{/block}
|
@@ -2,8 +2,12 @@
|
||||
{block tabissues} class="active"{/block}
|
||||
{block subtabs}
|
||||
<div id="sub-tabs">
|
||||
<a href="{url 'IDF_Views_Issue::index', array($project.shortname)}">{trans 'Recent issues'}</a>
|
||||
{if !$user.isAnonymous()} | <a href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a href="{url 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}">{trans 'My Issues'}</a>{/if}
|
||||
<a {if $inOpenIssues}class="active" {/if}href="{url 'IDF_Views_Issue::index', array($project.shortname)}">{trans 'Open issues'}</a>
|
||||
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}">{trans 'My Issues'}</a>{/if} |
|
||||
<form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get">
|
||||
<input accesskey="4" type="text" value="{$q}" name="q" size="20" />
|
||||
<input type="submit" name="s" value="{trans 'Search'}" />
|
||||
</form>
|
||||
{superblock}
|
||||
</div>
|
||||
{/block}
|
||||
|
@@ -4,7 +4,7 @@
|
||||
{$issues.render}
|
||||
{if !$user.isAnonymous()}
|
||||
{aurl 'url', 'IDF_Views_Issue::create', array($project.shortname)}
|
||||
<p><a href="{$url}">{trans 'New Issue'}</a></p>{/if}
|
||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'New Issue'}</a></p>{/if}
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
{extends "issues/base.html"}
|
||||
{block docclass}yui-t3{assign $inCreate = true}{/block}
|
||||
{block body}
|
||||
{if $form.errors}
|
||||
<div class="px-message-error">
|
||||
@@ -60,7 +61,7 @@
|
||||
<ul>
|
||||
<li>The steps to reproduce the problem.</li>
|
||||
<li>The version of the software and your operating system.</li>
|
||||
<li>Any information that can help the developpers to solve the issue.</li>
|
||||
<li>Any information that can help the developers to solve the issue.</li>
|
||||
<li><strong>Do not provide any password or confidential information!</strong></li>
|
||||
</ul>{/blocktrans}
|
||||
</div>
|
||||
|
@@ -4,7 +4,7 @@
|
||||
{$issues.render}
|
||||
{if !$user.isAnonymous()}
|
||||
{aurl 'url', 'IDF_Views_Issue::create', array($project.shortname)}
|
||||
<p><a href="{$url}">{trans 'New Issue'}</a></p>{/if}
|
||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'New Issue'}</a></p>{/if}
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
@@ -12,9 +12,9 @@
|
||||
{aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')}
|
||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
|
||||
|
||||
<p class="smaller">{foreach $project.getTagCloud() as $label}
|
||||
{assign $class = ''}{assign $i = 0}
|
||||
<p class="smaller">{foreach $project.getTagCloud($cloud) as $label}
|
||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
||||
<a href="{$url}" class="label"><strong>{$label.class}:</strong>{$label.name}</a>{/foreach}</p>
|
||||
|
||||
{if $class != $label.class}{if $i != 0}<br />{/if}<strong class="label">{$label.class}:</strong> {/if}
|
||||
<a href="{$url}" class="label">{$label.name}</a>,{assign $class = $label.class}{assign $i = $i + 1}{/foreach}</p>
|
||||
{/block}
|
||||
|
18
src/IDF/templates/issues/issue-created-email.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
{trans 'Hello,'}
|
||||
|
||||
{blocktrans}A new issue has been created and assigned
|
||||
to you:{/blocktrans}
|
||||
|
||||
{$issue.id} - {$issue.summary|safe}
|
||||
{trans 'Project:'} {$project.name|safe}
|
||||
{trans 'Status:'} {$issue.get_status.name|safe}
|
||||
{trans 'Reported by:'} {$issue.get_submitter|safe}
|
||||
{assign $tags = $issue.get_tags_list()}{if $tags.count()}{trans 'Labels:'}
|
||||
{foreach $tags as $tag} {$tag.class|safe}:{$tag.name|safe}
|
||||
{/foreach}{/if}
|
||||
{trans 'Description:'}
|
||||
|
||||
{$comment.content|safe}
|
||||
|
||||
--
|
||||
{trans 'Issue:'} {$url_base}{url 'IDF_Views_Issue::view', array($project.shortname, $issue.id)}
|
24
src/IDF/templates/issues/issue-updated-email.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
{trans 'Hello,'}
|
||||
|
||||
{blocktrans}The following issue has been updated:{/blocktrans}
|
||||
|
||||
{$issue.id} - {$issue.summary|safe}
|
||||
{trans 'Project:'} {$project.name|safe}
|
||||
{trans 'Status:'} {$issue.get_status.name}
|
||||
{trans 'Reported by:'} {$issue.get_submitter|safe}
|
||||
{trans 'URL:'} {$url_base}{url 'IDF_Views_Issue::view', array($project.shortname, $issue.id)}
|
||||
{assign $tags = $issue.get_tags_list()}{if $tags.count()}{trans 'Labels:'}
|
||||
{foreach $tags as $tag} {$tag.class|safe}:{$tag.name|safe}
|
||||
{/foreach}
|
||||
{/if}{trans 'Comments (last first):'}
|
||||
|
||||
{foreach $comments as $c}{assign $who = $c.get_submitter()}# {blocktrans}By {$who|safe}, {$c.creation_dtime|date}:{/blocktrans}
|
||||
|
||||
{if strlen($c.content) > 0}{$c.content|safe}{else}{trans '(No comments were given for this change.)'}{/if}{if $c.changedIssue()}
|
||||
{foreach $c.changes as $w => $v}
|
||||
{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if} {if $w == 'lb'}{assign $l = implode(', ', $v)}{$l}{else}{$v}{/if}{/foreach}{/if}
|
||||
|
||||
{/foreach}
|
||||
|
||||
--
|
||||
{trans 'Issue:'} {$url_base}{url 'IDF_Views_Issue::view', array($project.shortname, $issue.id)}
|
@@ -1,10 +1,10 @@
|
||||
{extends "issues/base.html"}
|
||||
{block docclass}yui-t2{/block}
|
||||
{block docclass}yui-t2{assign $inMyIssues = true}{/block}
|
||||
{block body}
|
||||
{$issues.render}
|
||||
{if !$user.isAnonymous()}
|
||||
{aurl 'url', 'IDF_Views_Issue::create', array($project.shortname)}
|
||||
<p><a href="{$url}">{trans 'New Issue'}</a></p>{/if}
|
||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'New Issue'}</a></p>{/if}
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
|
12
src/IDF/templates/issues/search.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{extends "issues/base.html"}
|
||||
{block docclass}yui-t2{/block}
|
||||
{block body}
|
||||
{$issues.render}
|
||||
{if !$user.isAnonymous()}
|
||||
{aurl 'url', 'IDF_Views_Issue::create', array($project.shortname)}
|
||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'New Issue'}</a></p>{/if}
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
<p><strong>{trans 'Found issues:'}</strong> {$issues.nb_items}</p>
|
||||
{/block}
|
@@ -1,19 +1,20 @@
|
||||
{extends "issues/base.html"}
|
||||
{block titleicon}{if $form}<form class="star" method="post" action="{url 'IDF_Views_Issue::star', array($project.shortname, $issue.id)}"><input type="image" src="{if $starred}{media '/idf/img/star.png'}{else}{media '/idf/img/star-grey.png'}{/if}" name="submit" /></form> {/if}{/block}
|
||||
{block body}
|
||||
{assign $i = 0}
|
||||
{assign $nc = $comments.count()}
|
||||
{foreach $comments as $c}
|
||||
<div class="issue-comment{if $i == 0} issue-comment-first{/if}{if $i == ($nc-1)} issue-comment-last{/if}" id="ic{$c.id}">
|
||||
{if $i == 0}{assign $who = $issue.get_submitter()}
|
||||
<p>{blocktrans}Reported by {$who}, {$c.creation_dtime|date}{/blocktrans}</p>
|
||||
{else}{assign $who = $c.get_submitter()}
|
||||
<div class="issue-comment{if $i == 0} issue-comment-first{/if}{if $i == ($nc-1)} issue-comment-last{/if}" id="ic{$c.id}">{assign $who = $c.get_submitter()}{aurl 'whourl', 'IDF_Views_User::view', array($who.login)}
|
||||
{if $i == 0}
|
||||
<p>{blocktrans}Reported by <a href="{$whourl}">{$who}</a>, {$c.creation_dtime|date}{/blocktrans}</p>
|
||||
{else}
|
||||
{aurl 'url', 'IDF_Views_Issue::view', array($project.shortname, $issue.id)}
|
||||
{assign $id = $c.id}
|
||||
{assign $url = $url~'#ic'~$c.id}
|
||||
<p>{blocktrans}Comment <a href="{$url}">{$i}</a> by {$who}, {$c.creation_dtime|date}{/blocktrans}</p>
|
||||
<p>{blocktrans}Comment <a href="{$url}">{$i}</a> by <a href="{$whourl}">{$who}</a>, {$c.creation_dtime|date}{/blocktrans}</p>
|
||||
{/if}
|
||||
|
||||
<pre class="issue-comment-text">{if strlen($c.content) > 0}{issuetext $c.content, $project}{else}<i>{trans '(No comments were given for this change.)'}</i>{/if}</pre>
|
||||
<pre class="issue-comment-text">{if strlen($c.content) > 0}{issuetext $c.content, $request}{else}<i>{trans '(No comments were given for this change.)'}</i>{/if}</pre>
|
||||
|
||||
{if $i> 0 and $c.changedIssue()}
|
||||
<div class="issue-changes">
|
||||
@@ -41,6 +42,10 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if $closed and (!$isOwner and !$isMember)}
|
||||
<p><img src="{media '/idf/img/warning.png'}" style="vertical-align: text-bottom;" alt=" " /> {blocktrans}This issue is marked as closed, add a comment only if you think this issue is still valid and more work is needed to fully fix it.{/blocktrans}</p>
|
||||
|
||||
{/if}
|
||||
<form method="post" enctype="multipart/form-data" action="{url 'IDF_Views_Issue::view', array($project.shortname, $issue.id)}" >
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
@@ -90,18 +95,18 @@
|
||||
{/block}
|
||||
{block context}
|
||||
<div class="issue-info">
|
||||
{assign $submitter = $issue.get_submitter()}
|
||||
<p><strong>{trans 'Created:'}</strong> <span class="nobrk">{$issue.creation_dtime|dateago}</span> <span class="nobrk">{blocktrans}by {$submitter}{/blocktrans}</span></p>
|
||||
<p>
|
||||
<strong>{trans 'Updated:'}</strong> <span class="nobrk">{$issue.modif_dtime|dateago}</span></p>
|
||||
{assign $submitter = $issue.get_submitter()}{aurl 'url', 'IDF_Views_User::view', array($submitter.login)}
|
||||
<p><strong>{trans 'Created:'}</strong> <span class="nobrk">{$issue.creation_dtime|dateago}</span> <span class="nobrk">{blocktrans}by <a href="{$url}">{$submitter}</a>{/blocktrans}</span></p>
|
||||
{if $issue.modif_dtime != $issue.creation_dtime}<p>
|
||||
<strong>{trans 'Updated:'}</strong> <span class="nobrk">{$issue.modif_dtime|dateago}</span></p>{/if}
|
||||
<p>
|
||||
<strong>{trans 'Status:'}</strong> {$issue.get_status.name}</p>
|
||||
<p>
|
||||
<strong>{trans 'Owner:'}</strong> {if $issue.get_owner == null}{trans 'No owner'}{else}{$issue.get_owner}{/if}
|
||||
</p>{assign $tags = $issue.get_tags_list()}{if $tags.count()}
|
||||
{if $issue.get_owner != null}<p>{aurl 'url', 'IDF_Views_User::view', array($issue.get_owner().login)}
|
||||
<strong>{trans 'Owner:'}</strong> <a href="{$url}">{$issue.get_owner}</a>
|
||||
</p>{/if}{assign $tags = $issue.get_tags_list()}{if $tags.count()}
|
||||
<p>
|
||||
<strong>{trans 'Labels:'}</strong><br />
|
||||
{foreach $issue.get_tags_list() as $tag}{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $tag.id, 'open')}
|
||||
{foreach $tags as $tag}{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $tag.id, 'open')}
|
||||
<span class="label"><a href="{$url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></span><br />
|
||||
{/foreach}
|
||||
</p>{/if}
|
||||
|
@@ -2,9 +2,12 @@
|
||||
{if $project}
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
// <!--
|
||||
{hotkey 'Shift+a', 'IDF_Views_Issue::create', array($project.shortname)}
|
||||
{hotkey 'Shift+r', 'IDF_Views_Issue::index', array($project.shortname)}
|
||||
{if !$user.isAnonymous()}
|
||||
{hotkey 'Shift+h', 'IDF_Views_Project::home', array($project.shortname)}
|
||||
{if $hasIssuesAccess}{hotkey 'Shift+a', 'IDF_Views_Issue::create', array($project.shortname)}
|
||||
{hotkey 'Shift+i', 'IDF_Views_Issue::index', array($project.shortname)}{/if}
|
||||
{if $hasDownloadsAccess}{hotkey 'Shift+d', 'IDF_Views_Download::index', array($project.shortname)}{/if}
|
||||
{if $hasSourceAccess}{hotkey 'Shift+s', 'IDF_Views_Source::treeBase', array($project.shortname, 'master')}{/if}
|
||||
{if $hasIssuesAccess and !$user.isAnonymous()}
|
||||
{hotkey 'Shift+m', 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}
|
||||
{hotkey 'Shift+w', 'IDF_Views_Issue::myIssues', array($project.shortname, 'owner')}
|
||||
{/if} //-->
|
||||
|
@@ -1,4 +1,5 @@
|
||||
{extends "base.html"}
|
||||
{block docclass}yui-t2{/block}
|
||||
{block tabhome} class="active"{/block}
|
||||
{block subtabs}
|
||||
<div id="sub-tabs">
|
||||
@@ -6,21 +7,27 @@
|
||||
</div>
|
||||
{/block}
|
||||
{block body}
|
||||
{$project.description}
|
||||
{$project.description|markdown}
|
||||
{/block}
|
||||
{block context}
|
||||
{if count($downloads) > 0}
|
||||
<p><strong>{trans 'Featured Downloads'}</strong><br />
|
||||
{foreach $downloads as $download}
|
||||
<span class="label"><a href="{url 'IDF_Views_Download::view', array($project.shortname, $download.id)}" title="{$download.summary}">{$download}</a></span><br />
|
||||
{/foreach}
|
||||
<span class="label"> </span><span class="note"><a href="{url 'IDF_Views_Download::index', array($project.shortname)}">{trans 'show more...'}</a></span>
|
||||
{/if}
|
||||
{assign $ko = 'owners'}
|
||||
{assign $km = 'members'}
|
||||
<p><strong>{trans 'Development Team'}</strong><br />
|
||||
{trans 'Admins'}<br />
|
||||
{foreach $team[$ko] as $owner}
|
||||
<span class="label">{$owner}</span><br />
|
||||
{foreach $team[$ko] as $owner}{aurl 'url', 'IDF_Views_User::view', array($owner.login)}
|
||||
<span class="label"><a class="label" href="{$url}">{$owner}</a></span><br />
|
||||
{/foreach}
|
||||
|
||||
{if count($team[$km]) > 0}
|
||||
{trans 'Happy Crew'}<br />
|
||||
{foreach $team[$km] as $member}
|
||||
<span class="label">{$member}</span><br />
|
||||
{foreach $team[$km] as $member}{aurl 'url', 'IDF_Views_User::view', array($member.login)}
|
||||
<span class="label"><a class="label" href="{$url}">{$member}</a></span><br />
|
||||
{/foreach}
|
||||
{/if}
|
||||
</p>
|
||||
|
@@ -2,8 +2,8 @@
|
||||
{block tabsource} class="active"{/block}
|
||||
{block subtabs}
|
||||
<div id="sub-tabs">
|
||||
<a {if $inSourceTree}class="active" {/if}href="{url 'IDF_Views_Source::treeBase', array($project.shortname, 'master')}">{trans 'Source Tree'}</a> |
|
||||
<a {if $inChangeLog}class="active" {/if}href="{url 'IDF_Views_Source::changeLog', array($project.shortname, 'master')}">{trans 'Change Log'}</a>
|
||||
<a {if $inSourceTree}class="active" {/if}href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}">{trans 'Source Tree'}</a> |
|
||||
<a {if $inChangeLog}class="active" {/if}href="{url 'IDF_Views_Source::changeLog', array($project.shortname, $project.getScmRoot())}">{trans 'Change Log'}</a>
|
||||
{if $inCommit}| {trans 'Commit'}{/if}
|
||||
</div>
|
||||
{/block}
|
||||
|
@@ -6,7 +6,6 @@
|
||||
<tr>
|
||||
<th>{trans 'Age'}</th>
|
||||
<th>{trans 'Message'}</th>
|
||||
{* <th>{trans 'Details'}</th> *}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -14,7 +13,7 @@
|
||||
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $change.commit)}
|
||||
<tr class="log">
|
||||
<td><a href="{$url}">{$change.date|dateago:"wihtout"}</a></td>
|
||||
<td>{$change.title}{if $change.full_message}<br /><br />{$change.full_message}{/if}</td>
|
||||
<td>{issuetext $change.title, $request}{if $change.full_message}<br /><br />{issuetext $change.full_message, $request}{/if}</td>
|
||||
</tr>
|
||||
<tr class="extra">
|
||||
<td colspan="2">
|
||||
@@ -29,11 +28,23 @@
|
||||
</table>
|
||||
{/block}
|
||||
{block context}
|
||||
{if $scm == 'git'}
|
||||
<p><strong>{trans 'Branches:'}</strong><br />
|
||||
{foreach $branches as $branch}
|
||||
{aurl 'url', 'IDF_Views_Source::changeLog', array($project.shortname, $branch)}
|
||||
<span class="label{if $commit == $branch} active{/if}"><a href="{$url}" class="label">{$branch}</a></span><br />
|
||||
{/foreach}
|
||||
</p>
|
||||
{/if}
|
||||
{if $scm == 'svn'}
|
||||
<form class="star" action="{url 'IDF_Views_Source::changelogRev', array($project.shortname)}" method="get">
|
||||
<p><strong>{trans 'Revison:'}</strong> {$commit}</p>
|
||||
<p>
|
||||
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5" />
|
||||
<input type="submit" name="s" value="{trans 'Go to revision'}" />
|
||||
</p>
|
||||
</form>
|
||||
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
|
@@ -15,8 +15,9 @@
|
||||
<th><strong>{trans 'Tree:'}</strong></th><td class="mono"><a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $commit)}" title="{trans 'View corresponding source tree'}">{$cobject.tree}</a><br /><br /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{trans 'Message:'}</strong></th><td>{issuetext $cobject.title, $project}{if isset($cobject.full_message)}<br /><br />{issuetext $cobject.full_message, $project}{/if}</td>
|
||||
<th><strong>{trans 'Message:'}</strong></th><td>{issuetext $cobject.title, $request}{if isset($cobject.full_message)}<br /><br />{issuetext $cobject.full_message, $request}{/if}</td>
|
||||
</tr>
|
||||
{if count($diff.files)}
|
||||
<tr>
|
||||
<th><strong>{trans 'Files:'}</strong></th>
|
||||
<td>
|
||||
@@ -26,18 +27,22 @@
|
||||
{/foreach}
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
</table>
|
||||
{if count($diff.files)}
|
||||
<h2>{trans 'Change Details'}</h2>
|
||||
|
||||
{$diff.as_html()|safe}
|
||||
|
||||
{/if}
|
||||
{/block}
|
||||
{block context}
|
||||
{if $scm == 'git'}
|
||||
<p><strong>{trans 'Branches:'}</strong><br />
|
||||
{foreach $branches as $branch}
|
||||
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $branch)}
|
||||
<span class="label{if $commit == $branch} active{/if}"><a href="{$url}" class="label">{$branch}</a></span><br />
|
||||
{/foreach}
|
||||
</p>
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
{block docclass}yui-t1{assign $inSourceTree=true}{/block}
|
||||
{block body}
|
||||
<h2><a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $commit)}">{trans 'Root'}</a><span class="sep">/</span>{if $breadcrumb}{$breadcrumb|safe}{/if}</h2>
|
||||
|
||||
<table summary="" class="tree-list">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -41,6 +42,9 @@
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
{aurl 'url', 'IDF_Views_Source::download', array($project.shortname, $commit)}
|
||||
<p class="right soft"><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/package-grey.png'}" alt="{trans 'Archive'}" align="bottom" /></a> <a href="{$url}">{trans 'Download this version'}</a> {trans 'or'} <kbd>git clone {$project.getRemoteAccessUrl()}</kbd></p>
|
||||
|
||||
|
||||
{/block}
|
||||
{block context}
|
72
src/IDF/templates/source/svn/tree.html
Normal file
@@ -0,0 +1,72 @@
|
||||
{extends "source/base.html"}
|
||||
{block docclass}yui-t1{assign $inSourceTree=true}{/block}
|
||||
{block body}
|
||||
<h2><a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $commit)}">{trans 'Root'}</a><span class="sep">/</span>{if $breadcrumb}{$breadcrumb|safe}{/if}</h2>
|
||||
|
||||
<table summary="" class="tree-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">{trans 'File'}</th>
|
||||
<th>{trans 'Age'}</th>
|
||||
<th>{trans 'Rev'}</th>
|
||||
<th>{trans 'Message'}</th>
|
||||
<th>{trans 'Size'}</th>
|
||||
</tr>
|
||||
</thead>{if !$tree_in || $props}
|
||||
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
||||
<tfoot>
|
||||
{if $props}
|
||||
<tr><th colspan="6">
|
||||
<ul>
|
||||
{foreach $props as $prop => $val}
|
||||
<li>{trans 'Property'} <strong>{$prop}</strong> {trans 'set to:'} <em>{$val}</em></li>
|
||||
{/foreach}
|
||||
</ul>
|
||||
</th></tr>
|
||||
{/if}
|
||||
{if !$tree_in}
|
||||
<tr><th colspan="6">{blocktrans}Source at commit <a class="mono" href="{$url}">{$commit}</a> created {$cobject.date|dateago}.{/blocktrans}<br />
|
||||
<span class="smaller">{blocktrans}By {$cobject.author|strip_tags|trim}, {$cobject.title}{/blocktrans}</span>
|
||||
</th></tr>
|
||||
{/if}
|
||||
</tfoot>
|
||||
{/if}<tbody>
|
||||
{if $base}
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>
|
||||
<a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $prev)}">..</a></td>
|
||||
<td colspan="3"></td>
|
||||
</tr>
|
||||
{/if}
|
||||
{foreach $files as $file}
|
||||
{aurl 'url', 'IDF_Views_Source::tree', array($project.shortname, $commit, $file.fullpath)}
|
||||
<tr>
|
||||
<td class="fileicon"><img src="{media '/idf/img/'~$file.type~'.png'}" alt="{$file.type}" /></td>
|
||||
|
||||
<td><a href="{$url}">{$file.file}</a></td>
|
||||
<td><span class="smaller">{$file.date|dateago:"wihtout"}</span></td>
|
||||
<td>{$file.rev}</td>
|
||||
<td{if $file.type != 'blob'} colspan="2"{/if}><span class="smaller">{$file.log|nl2br}</span></td>
|
||||
{if $file.type == 'blob'}
|
||||
<td>{$file.size|size}</td>
|
||||
{/if}
|
||||
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="right soft"><kbd>svn co -r {$commit} {$project.getRemoteAccessUrl()}</kbd></p>
|
||||
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
<form class="star" action="{url 'IDF_Views_Source::treeRev', array($project.shortname)}" method="get">
|
||||
<p><strong>{trans 'Revison:'}</strong> {$commit}</p>
|
||||
<p>
|
||||
<input accesskey="4" type="text" value="{$commit}" name="rev" size="5" />
|
||||
<input type="hidden" name="sourcefile" value="{$base}"/>
|
||||
<input type="submit" name="s" value="{trans 'Go to revision'}" /></p>
|
||||
</form>
|
||||
|
||||
{/block}
|
59
src/IDF/templates/user/myaccount.html
Normal file
@@ -0,0 +1,59 @@
|
||||
{extends "base-simple.html"}
|
||||
{block body}
|
||||
{if $form.errors}
|
||||
<div class="px-message-error">
|
||||
<p>{trans 'Oups, please check the form for errors.'}</p>
|
||||
{if $form.get_top_errors}
|
||||
{$form.render_top_errors|unsafe}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<form method="post" action=".">
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<th>{trans 'Login:'}</th>{aurl 'url', 'IDF_Views_User::view', array($user.login)}
|
||||
<td><a href="{$url}">{$user.login}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$form.f.first_name.labelTag}:</th>
|
||||
<td>{if $form.f.first_name.errors}{$form.f.first_name.fieldErrors}{/if}
|
||||
{$form.f.first_name|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><strong>{$form.f.last_name.labelTag}:</strong></th>
|
||||
<td>{if $form.f.last_name.errors}{$form.f.last_name.fieldErrors}{/if}
|
||||
{$form.f.last_name|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$form.f.password.labelTag}:</th>
|
||||
<td>{if $form.f.password.errors}{$form.f.password.fieldErrors}{/if}
|
||||
{$form.f.password|unsafe}<br />
|
||||
<span class="helptext">{$form.f.password.help_text}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{$form.f.password2.labelTag}:</th>
|
||||
<td>{if $form.f.password2.errors}{$form.f.password2.fieldErrors}{/if}
|
||||
{$form.f.password2|unsafe}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><input type="submit" value="{trans 'Update Your Account'}" name="submit" /> | <a href="{url 'IDF_Views::index'}">{trans 'Cancel'}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{/block}
|
||||
{block context}
|
||||
<div class="issue-submit-info">
|
||||
<p>{trans 'If possible, use your real name. By using your real name, people will have more trust in your comments and remarks.'}</p>
|
||||
</div>{/block}
|
||||
{block javascript}<script type="text/javascript">
|
||||
document.getElementById('id_first_name').focus()
|
||||
</script>
|
||||
{/block}
|
||||
|
28
src/IDF/templates/user/public.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{extends "base-simple.html"}
|
||||
{block body}
|
||||
<table class="form" summary="">
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>{$member}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{trans 'Last time seen:'}</th>
|
||||
<td>{$member.last_login|dateago}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{trans 'Member since:'}</th>
|
||||
<td>{$member.date_joined|date}</td>
|
||||
</tr>
|
||||
</table>
|
||||
{/block}
|
||||
{block context}
|
||||
<div class="issue-submit-info">
|
||||
<p>{blocktrans}You are looking at the public profile of {$member}.{/blocktrans}</p>
|
||||
</div>
|
||||
<h2>{trans 'Projects'}</h2>
|
||||
<ul>{foreach $projects as $p}
|
||||
<li><a href="{url 'IDF_Views_Project::home', array($p.shortname)}">{$p}</a></li>
|
||||
{/foreach}</ul>
|
||||
{/block}
|
||||
|
||||
|
@@ -27,10 +27,32 @@
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dellink {
|
||||
float: right;
|
||||
position: relative;
|
||||
margin-top: -1.6em;
|
||||
}
|
||||
|
||||
.dellink a {
|
||||
color: #a00;
|
||||
}
|
||||
|
||||
a.userw {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.soft {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.soft a {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
div.context {
|
||||
padding-left: 1em;
|
||||
}
|
||||
@@ -38,6 +60,10 @@ div.context {
|
||||
/**
|
||||
* Form
|
||||
*/
|
||||
form.star {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
table.form th, table.form td {
|
||||
border: none;
|
||||
vertical-align: top;
|
||||
@@ -188,6 +214,10 @@ a.label {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #204a87;
|
||||
}
|
||||
|
||||
span.nobrk {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -300,6 +330,11 @@ table.tree-list tfoot th a {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
table.tree-list tfoot th ul {
|
||||
text-align: left;
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
table.tree-list tr.log {
|
||||
border-bottom: 1px solid #e7ebe3;
|
||||
/* background-color: #eef2ea !important; */
|
||||
@@ -444,3 +479,19 @@ table.diff tr.diff-next {
|
||||
table.diff tr.diff-next td {
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download
|
||||
*/
|
||||
div.download-file {
|
||||
padding: 1em 1em 1em 3em;
|
||||
background: url("../img/down-large.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 1em 1em;
|
||||
font-size: 140%;
|
||||
margin-bottom: 3em;
|
||||
background-color: #bbe394;
|
||||
width: 40%;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
BIN
www/media/idf/img/add.png
Normal file
After Width: | Height: | Size: 323 B |
BIN
www/media/idf/img/down-large.png
Normal file
After Width: | Height: | Size: 874 B |
BIN
www/media/idf/img/package-grey.png
Normal file
After Width: | Height: | Size: 576 B |
BIN
www/media/idf/img/package.png
Normal file
After Width: | Height: | Size: 540 B |
BIN
www/media/idf/img/powered-by-indefero.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
www/media/idf/img/star-grey.png
Normal file
After Width: | Height: | Size: 744 B |
BIN
www/media/idf/img/star.png
Normal file
After Width: | Height: | Size: 819 B |
BIN
www/media/idf/img/trash.png
Normal file
After Width: | Height: | Size: 655 B |
BIN
www/media/idf/img/warning.png
Normal file
After Width: | Height: | Size: 603 B |