Compare commits
146 Commits
master
...
feature.be
Author | SHA1 | Date | |
---|---|---|---|
|
b36b8e3afb | ||
|
dc31155de1 | ||
|
0bae69908b | ||
|
47a077bc82 | ||
|
836ff71364 | ||
|
576c06ffaf | ||
|
352dc3e179 | ||
|
aa164936f4 | ||
|
9a93acd1a5 | ||
|
587aa11cda | ||
|
d04ecd60c4 | ||
|
aa68fe3485 | ||
|
e408fe8733 | ||
|
836986462a | ||
|
51c6cdb20d | ||
|
766232f29b | ||
|
2ed021f30b | ||
|
899fe561df | ||
|
67d8936083 | ||
|
78f5cef5bd | ||
|
8928b1654c | ||
|
977fa0d1d4 | ||
|
1d89cec2cf | ||
|
6c6b7d6bb2 | ||
|
f92e88e9b4 | ||
|
6e58899fdf | ||
|
1513598420 | ||
|
9cfc060760 | ||
|
a531e34ec2 | ||
|
2cce23b5b4 | ||
|
e518bc9b68 | ||
|
8e02d05ba9 | ||
|
f131083315 | ||
|
39ba5b37ef | ||
|
002fa05c7f | ||
|
1a52133fd4 | ||
|
30900f7196 | ||
|
b753cf0837 | ||
|
53ab5b6aff | ||
|
78a0402351 | ||
|
5b5705fe90 | ||
|
f08b5c5e3f | ||
|
aa87acd432 | ||
|
7af7ef8357 | ||
|
627bc4e45f | ||
|
909c76ebfb | ||
|
0899ba8515 | ||
|
b7c0b40491 | ||
|
48257ccfed | ||
|
269949a65f | ||
|
c2de7123e4 | ||
|
e0c6dcd5a4 | ||
|
734ddda363 | ||
|
02cd448f89 | ||
|
5fc3a987de | ||
|
be39d72d3c | ||
|
045eb766f1 | ||
|
22d4bd0e6f | ||
|
5a7bf49cbb | ||
|
a3dd1c45f3 | ||
|
be7725694e | ||
|
366d278182 | ||
|
5f008a14f5 | ||
|
21a8c281ec | ||
|
51dde5766d | ||
|
61d7b4a58d | ||
|
19b35565a2 | ||
|
baa88412b9 | ||
|
6fb9b72e22 | ||
|
b75884c57e | ||
|
603188f6ce | ||
|
15442140cf | ||
|
9f877d4309 | ||
|
8631529268 | ||
|
96bc198b0f | ||
|
146ffb5f4c | ||
|
867c3d3382 | ||
|
75b0f27fe2 | ||
|
4b001d8f03 | ||
|
a7bec96a80 | ||
|
a8706e38ca | ||
|
265fd41717 | ||
|
67c23ffe24 | ||
|
e9a09889e4 | ||
|
e6756a2072 | ||
|
f4050b8a76 | ||
|
bb4fa7ca2f | ||
|
2648603f24 | ||
|
b7a9a1c8fd | ||
|
d45566d692 | ||
|
4411086f29 | ||
|
0b3ce03036 | ||
|
027886737d | ||
|
35f45015ea | ||
|
618f412bed | ||
|
6ab9c754a5 | ||
|
c59332c8f8 | ||
|
32d9d04b4b | ||
|
62d0fb6eee | ||
|
bc82ee24d8 | ||
|
6ab1f4a4f0 | ||
|
3e6527bab3 | ||
|
9b7691c1ae | ||
|
c3cd494386 | ||
|
fba5841bdc | ||
|
da7fc3e7e3 | ||
|
00ebe1633c | ||
|
f63bfcb4f6 | ||
|
177cf836b4 | ||
|
04069871bb | ||
|
31469204e0 | ||
|
9b148c8c4a | ||
|
98f4eac82a | ||
|
29d966cdb3 | ||
|
23d2bd552c | ||
|
41cfbbd0d9 | ||
|
cc89a7e6f8 | ||
|
c486fe98fb | ||
|
f0ac256ff6 | ||
|
e4b3adb2f5 | ||
|
58a5bc46d9 | ||
|
6e5c3a551d | ||
|
52f8261d8c | ||
|
721c385993 | ||
|
9c80de19d7 | ||
|
4ffd11caf5 | ||
|
f2c4faf054 | ||
|
bc54b663e0 | ||
|
6f1bb309d4 | ||
|
cdedaa4604 | ||
|
2130b327df | ||
|
3e238bea0b | ||
|
266c297632 | ||
|
4477b07bc6 | ||
|
74b44186d2 | ||
|
c2bf1bac38 | ||
|
c279313048 | ||
|
0301ba0336 | ||
|
5e6d61b3a7 | ||
|
4e00051a10 | ||
|
38e6e4f8d3 | ||
|
dfa223b39e | ||
|
0a8d771c11 | ||
|
5afd073ff3 | ||
|
46fda14e08 | ||
|
bbf9ef8b3d |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
src/IDF/version.php export-subst
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,3 +9,6 @@ indefero-*.zip
|
|||||||
src/IDF/conf/path.php
|
src/IDF/conf/path.php
|
||||||
.tx/config
|
.tx/config
|
||||||
src/IDF/locale/idf.pot.bak
|
src/IDF/locale/idf.pot.bak
|
||||||
|
test/test.db
|
||||||
|
test/tmp
|
||||||
|
test/config.php
|
||||||
|
52
AUTHORS
52
AUTHORS
@ -1,30 +1,42 @@
|
|||||||
InDefero was originally created during summer 2008
|
InDefero was originally created during summer 2008
|
||||||
by Loïc d'Anterroches with the support of Céondo Ltd.
|
by Loïc d'Anterroches with the support of Céondo Ltd.
|
||||||
|
|
||||||
Much appreciated contributors:
|
Much appreciated contributors (in alphabetical order):
|
||||||
|
|
||||||
Nicolas Lassalle <http://www.beroot.org/> - Subversion support
|
Adrien Bustany <madcat@mymadcat.com>
|
||||||
bohwaz <http://bohwaz.net/>
|
Andrew Nguyen <andrew-git-indefero@na-consulting.net>
|
||||||
Benjamin Jorand <benjamin.jorand@gmail.com> - Mercurial support
|
Baptiste Durand-Bret <bathizte@ozazar.org>
|
||||||
Baptiste Michaud <bactisme@gmail.com> - Subversion synchronization
|
Baptiste Michaud <bactisme@gmail.com> - Subversion sync
|
||||||
Julien Issler
|
Benjamin Jorand <benjamin.jorand@gmail.com> - Mercurial support
|
||||||
|
Brenda Wallace <shiny@cpan.org>
|
||||||
|
Brian Armstrong <brianar>
|
||||||
|
Charles Melbye <charlie@yourwiki.net>
|
||||||
|
Ciaran Gultnieks <ciaran@ciarang.com>
|
||||||
|
David Feeney <davidf>
|
||||||
|
Denis Kot <denis.kot@gmail.com> - Russian translation
|
||||||
|
Dmitry Dulepov <dmitryd>
|
||||||
|
Fernando Sayago Gil <mikados.mikados@gmail.com> - Spanish translation
|
||||||
|
Jakub Viták <mainiak@gmail.com> - Czech translation
|
||||||
|
Janez Troha <http://www.dz0ny.info> - Slovenian translation
|
||||||
|
Jean-Philippe Fleury <jpfleury>
|
||||||
|
Jerry <lxb429@gmail.com> - Chinese translation
|
||||||
|
Julien Issler <julien@issler.net>
|
||||||
|
Ludovic Bellière <xrogaan>
|
||||||
Manuel Eidenberger <eidenberger@gmail.com>
|
Manuel Eidenberger <eidenberger@gmail.com>
|
||||||
Ciaran Gultnieks
|
Matthew Dawson <mjd>
|
||||||
|
Matías Halles <matias@halles.cl>
|
||||||
Mehdi Kabab <http://pioupioum.fr/>
|
Mehdi Kabab <http://pioupioum.fr/>
|
||||||
Sindre R. Myren
|
Nicolas Lassalle <nicolas@beroot.org> - Subversion support
|
||||||
Patrick Georgi <patrick.georgi@coresystems.de>
|
Patrick Georgi <patrick.georgi@coresystems.de>
|
||||||
Adrien Bustany
|
Raphaël Emourgeon <raphael>
|
||||||
Charles Melbye
|
Samuel Suther <info@suther.de> - German translation
|
||||||
Baptiste Durand-Bret
|
Sindre R. Myren <sindrero@stud.ntnu.no>
|
||||||
Andrew Nguyen
|
Stewart Platt <stew@futurete.ch>
|
||||||
David Feeney
|
Thomas Keller <me@thomaskeller.biz> - Monotone support
|
||||||
Denis Kot <denis.kot@gmail.com>
|
Vladimir Solomatin <slash>
|
||||||
Samuel Suther
|
William Martin <william.martin@lcpc.fr>
|
||||||
Ludovic Bellière
|
Xavier Brochard <xavier@alternatif.org>
|
||||||
Brian Armstrong
|
bohwaz <http://bohwaz.net/>
|
||||||
Raphaël Emourgeon
|
|
||||||
Jakub Viták
|
|
||||||
Vladimir Solomatin
|
|
||||||
|
|
||||||
And all the nice users who spent time reporting issues and promoting
|
And all the nice users who spent time reporting issues and promoting
|
||||||
the project. The project could not live without them.
|
the project. The project could not live without them.
|
||||||
|
@ -104,12 +104,13 @@ without first talking to us.
|
|||||||
|
|
||||||
## I am a translator
|
## I am a translator
|
||||||
|
|
||||||
We currently use (transifex)[http://trac.transifex.org] to help our
|
We currently use [transifex](http://trac.transifex.org) to help our
|
||||||
users to translate indefero. You don't have to use it, but it's an
|
users translate indefero. You don't have to use it, but it's an easy
|
||||||
easy way to do the job. You can visit the indefero page at transifex
|
way to do the job. You can visit the indefero page at transifex here:
|
||||||
here : http://www.transifex.net/projects/p/indefero/c/indefero/
|
|
||||||
|
http://www.transifex.net/projects/p/indefero/
|
||||||
|
|
||||||
Please understand that your changes will not be commited instantly,
|
Please understand that your changes will not be commited instantly,
|
||||||
but are sent to the maintainers e-mails before. Then, your changes
|
but are sent to the maintainers e-mails before. Then, your changes
|
||||||
will not be in the main repository until da-loic push the changes. In
|
will not be in the main repository until the maintainer pushs the
|
||||||
that way, try to do big changes with less submissions.
|
changes. In that way, try to do big changes with less submissions.
|
||||||
|
@ -4,6 +4,12 @@ The installation of InDefero is composed of 2 parts, first the
|
|||||||
installation of the [Pluf framework](http://www.pluf.org) and second,
|
installation of the [Pluf framework](http://www.pluf.org) and second,
|
||||||
the installation of InDefero by itself.
|
the installation of InDefero by itself.
|
||||||
|
|
||||||
|
## PHP modules for indefero
|
||||||
|
|
||||||
|
Indefero need the GD module for PHP. It's named "php5-gd" in debian.
|
||||||
|
|
||||||
|
$ apt-get install php5-gd
|
||||||
|
|
||||||
## Recommended Layout of the Files
|
## Recommended Layout of the Files
|
||||||
|
|
||||||
If your server document root is in `/var/www` a good thing is to keep
|
If your server document root is in `/var/www` a good thing is to keep
|
||||||
@ -37,6 +43,7 @@ docroot.
|
|||||||
$ sudo pear upgrade-all
|
$ sudo pear upgrade-all
|
||||||
$ sudo pear install --alldeps Mail
|
$ sudo pear install --alldeps Mail
|
||||||
$ sudo pear install --alldeps Mail_mime
|
$ sudo pear install --alldeps Mail_mime
|
||||||
|
$ sudo pear install --alldeps Console_Getopt
|
||||||
|
|
||||||
If you already have some of the PEAR packages installed with your
|
If you already have some of the PEAR packages installed with your
|
||||||
distribution, the `Mail` package is often not up-to-date,
|
distribution, the `Mail` package is often not up-to-date,
|
||||||
@ -125,6 +132,7 @@ The documentation is available in the `doc` folder.
|
|||||||
* Subversion: `doc/syncsvn.mdtext`.
|
* Subversion: `doc/syncsvn.mdtext`.
|
||||||
* Mercurial: `doc/syncmercurial.mdtext`.
|
* Mercurial: `doc/syncmercurial.mdtext`.
|
||||||
* Git: `doc/syncgit.mdtext`.
|
* Git: `doc/syncgit.mdtext`.
|
||||||
|
* Monotone: `doc/syncmonotone.mdtext`
|
||||||
|
|
||||||
## For the Apache Webserver Users
|
## For the Apache Webserver Users
|
||||||
|
|
||||||
|
103
Makefile
103
Makefile
@ -22,25 +22,36 @@
|
|||||||
# sudo apt-get install python-setuptools
|
# sudo apt-get install python-setuptools
|
||||||
# sudo easy_install -U transifex-client
|
# sudo easy_install -U transifex-client
|
||||||
|
|
||||||
PLUF_PATH=$(shell php -r "require_once('src/IDF/conf/path.php'); echo PLUF_PATH;")
|
|
||||||
|
|
||||||
all help:
|
|
||||||
@echo "Rules for generate tarball :"
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
@printf "Rules for generating distributable files :\n"
|
||||||
@for b in `git branch | sed "s/^. //g"`; do \
|
@for b in `git branch | sed "s/^. //g"`; do \
|
||||||
echo -e "\t"$$b"_tarball - Generate a zip archive of the "$$b" branch."; \
|
printf "\t"$$b"-zipfile - Generate a zip archive of the "$$b" branch.\n"; \
|
||||||
done
|
done
|
||||||
@echo -e "\nRules for internationnalization :";
|
@printf "\nRules for internationalization :\n";
|
||||||
@echo -e "\tpot-update - Update the POT file from HTML template and PHP source, then merge it with PO file"
|
@printf "\tpot-update - Update the POT file from HTML templates and PHP sources, then merge it with PO file.\n"
|
||||||
@echo -e "\tpot-push - Send the POT file on transifex server"
|
@printf "\tpot-push - Send the POT file to the transifex server.\n"
|
||||||
@echo -e "\tpo-update - Merge POT file into PO file. POT is not regenerated."
|
@printf "\tpo-update - Merge the POT file into the PO file. The POT is not regenerated.\n"
|
||||||
@echo -e "\tpo-push - Send the all PO file on transifex server"
|
@printf "\tpo-push - Send the all PO files to the transifex server.\n"
|
||||||
@echo -e "\tpo-pull - Get all PO file from transifex server"
|
@printf "\tpo-pull - Get all PO files from the transifex server.\n"
|
||||||
|
@printf "\tpo-stats - Show translation statistics of all PO files.\n"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Internationnalization rule, POT & PO file manipulation
|
# Internationalization rule, POT & PO file manipulation
|
||||||
#
|
#
|
||||||
|
.PHONY: pluf_path
|
||||||
|
pluf_path:
|
||||||
|
ifeq (src/IDF/conf/path.php, $(wildcard src/IDF/conf/path.php))
|
||||||
|
PLUF_PATH=$(shell php -r "require_once('src/IDF/conf/path.php'); echo PLUF_PATH;")
|
||||||
|
else
|
||||||
|
@printf "File 'src/IDF/conf/path.php' don't exist. Please configure it !\n"
|
||||||
|
@exit 1
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: pot-update po-update
|
.PHONY: pot-update po-update
|
||||||
pot-update:
|
pot-update: pluf_path
|
||||||
# Backup pot file
|
# Backup pot file
|
||||||
@if [ -e src/IDF/locale/idf.pot ]; then \
|
@if [ -e src/IDF/locale/idf.pot ]; then \
|
||||||
mv -f src/IDF/locale/idf.pot src/IDF/locale/idf.pot.bak; \
|
mv -f src/IDF/locale/idf.pot src/IDF/locale/idf.pot.bak; \
|
||||||
@ -49,19 +60,20 @@ pot-update:
|
|||||||
# Extract string
|
# Extract string
|
||||||
@cd src; php $(PLUF_PATH)/extracttemplates.php IDF/conf/idf.php IDF/gettexttemplates
|
@cd src; php $(PLUF_PATH)/extracttemplates.php IDF/conf/idf.php IDF/gettexttemplates
|
||||||
@cd src; for phpfile in `find . -iname "*.php"`; do \
|
@cd src; for phpfile in `find . -iname "*.php"`; do \
|
||||||
echo "Parsing file : "$$phpfile; \
|
printf "Parsing file : "$$phpfile"\n"; \
|
||||||
xgettext -o idf.pot -p ./IDF/locale/ --from-code=UTF-8 -j --keyword --keyword=__ --keyword=_n:1,2 -L PHP $$phpfile ; \
|
xgettext -o idf.pot -p ./IDF/locale/ --from-code=UTF-8 -j \
|
||||||
|
--keyword --keyword=__ --keyword=_n:1,2 -L PHP $$phpfile ; \
|
||||||
done
|
done
|
||||||
# Remove tmp folder
|
# Remove tmp folder
|
||||||
rm -Rf src/IDF/gettexttemplates
|
rm -Rf src/IDF/gettexttemplates
|
||||||
# Update PO
|
# Update PO
|
||||||
@make po-update
|
@make po-update
|
||||||
|
|
||||||
po-update:
|
po-update: pluf_path
|
||||||
@for pofile in `ls src/IDF/locale/*/idf.po`; do \
|
@for pofile in `ls src/IDF/locale/*/idf.po`; do \
|
||||||
echo "Updating file : "$$pofile; \
|
printf "Updating file : "$$pofile"\n"; \
|
||||||
msgmerge -v -U $$pofile src/IDF/locale/idf.pot; \
|
msgmerge -v -U $$pofile src/IDF/locale/idf.pot; \
|
||||||
echo ; \
|
printf "\n"; \
|
||||||
done
|
done
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -72,22 +84,22 @@ check-tx-config:
|
|||||||
@if [ ! -e .tx/config ]; then \
|
@if [ ! -e .tx/config ]; then \
|
||||||
mkdir -p .tx; \
|
mkdir -p .tx; \
|
||||||
touch .tx/config; \
|
touch .tx/config; \
|
||||||
echo "[main]" >> .tx/config; \
|
printf "[main]\n" >> .tx/config; \
|
||||||
echo "host = http://www.transifex.net" >> .tx/config; \
|
printf "host = http://www.transifex.net\n" >> .tx/config; \
|
||||||
echo "" >> .tx/config; \
|
printf "\n" >> .tx/config; \
|
||||||
echo "[indefero.idfpot]" >> .tx/config; \
|
printf "[indefero.idfpot]\n" >> .tx/config; \
|
||||||
echo "file_filter = src/IDF/locale/<lang>/idf.po" >> .tx/config; \
|
printf "file_filter = src/IDF/locale/<lang>/idf.po\n" >> .tx/config; \
|
||||||
echo "source_file = src/IDF/locale/idf.pot" >> .tx/config; \
|
printf "source_file = src/IDF/locale/idf.pot\n" >> .tx/config; \
|
||||||
echo "source_lang = en" >> .tx/config; \
|
printf "source_lang = en\n" >> .tx/config; \
|
||||||
fi
|
fi
|
||||||
@if [ ! -e $(HOME)/.transifexrc ]; then \
|
@if [ ! -e $(HOME)/.transifexrc ]; then \
|
||||||
touch $(HOME)/.transifexrc; \
|
touch $(HOME)/.transifexrc; \
|
||||||
echo "[http://www.transifex.net]" >> $(HOME)/.transifexrc; \
|
printf "[http://www.transifex.net]\n" >> $(HOME)/.transifexrc; \
|
||||||
echo "username = " >> $(HOME)/.transifexrc; \
|
printf "username = \n" >> $(HOME)/.transifexrc; \
|
||||||
echo "token = " >> $(HOME)/.transifexrc; \
|
printf "token = \n" >> $(HOME)/.transifexrc; \
|
||||||
echo "password = " >> $(HOME)/.transifexrc; \
|
printf "password = \n" >> $(HOME)/.transifexrc; \
|
||||||
echo "hostname = http://www.transifex.net" >> $(HOME)/.transifexrc; \
|
printf "hostname = http://www.transifex.net\n" >> $(HOME)/.transifexrc; \
|
||||||
echo "You must edit the file ~/.transifexrc to setup your transifex account (login & password) !"; \
|
printf "You must edit the file ~/.transifexrc to setup your transifex account (login & password) !\n"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -98,13 +110,32 @@ po-push: check-tx-config
|
|||||||
@tx push -t
|
@tx push -t
|
||||||
|
|
||||||
po-pull: check-tx-config
|
po-pull: check-tx-config
|
||||||
|
# Save PO
|
||||||
|
@for pofile in `ls src/IDF/locale/*/idf.po`; do \
|
||||||
|
cp $$pofile $$pofile".save"; \
|
||||||
|
done
|
||||||
|
# Get new one
|
||||||
@tx pull -a
|
@tx pull -a
|
||||||
|
# Merge Transifex PO into local PO (so fuzzy entry is correctly saved)
|
||||||
|
@for pofile in `ls src/IDF/locale/*/idf.po`; do \
|
||||||
|
msgmerge -U $$pofile".save" $$pofile; \
|
||||||
|
rm -f $$pofile; \
|
||||||
|
mv $$pofile".save" $$pofile; \
|
||||||
|
done
|
||||||
|
|
||||||
|
po-stats:
|
||||||
|
@msgfmt --statistics -v src/IDF/locale/idf.pot
|
||||||
|
@for pofile in `ls src/IDF/locale/*/idf.po`; do \
|
||||||
|
msgfmt --statistics -v $$pofile; \
|
||||||
|
done
|
||||||
|
|
||||||
#
|
#
|
||||||
# Generic rule to build a tarball of indefero for a specified branch
|
# Generic rule to build a zipfile of indefero for a specified branch
|
||||||
# ex: make master_tarball
|
# ex: make master_zipfile
|
||||||
# make dev_tarball
|
# make develop_zipfile
|
||||||
#
|
#
|
||||||
%_tarball:
|
%-zipfile:
|
||||||
@git archive --format=zip --prefix="indefero/" $(@:_tarball=) > indefero-$(@:_tarball=)-`git log $(@:_tarball=) -n 1 --pretty=format:%H`.zip
|
@git archive --format=zip --prefix="indefero/" $(@:-zipfile=) \
|
||||||
|
> indefero-$(@:-zipfile=)-`git log $(@:-zipfile=) -n 1 \
|
||||||
|
--pretty=format:%h`.zip
|
||||||
|
|
||||||
|
104
NEWS.mdtext
Normal file
104
NEWS.mdtext
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# InDefero 1.2 - xxx xxx xx xx:xx 2011 UTC
|
||||||
|
|
||||||
|
## New Features
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
- monotone zip archive entries now all carry the revision date as mtime (issue 645)
|
||||||
|
- Timeline only displays filter options for items a user has actually access to (issue 655)
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
# InDefero 1.1.1 - Mon Mar 28 15:52 2011 UTC
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
- Fix an incompatibility with Python 3.1 in gitserve.py (issue 554)
|
||||||
|
- Fix PHP error when the commit view shows a commit with changed binary files (issue 643)
|
||||||
|
- A migration problem prevented the preferences page being displayed properly (issues 644 and 653)
|
||||||
|
- Fix PHP error when trying to create Mercurial source archives (issue 648)
|
||||||
|
- Improve the French translation (issue 651)
|
||||||
|
- Registration page missed a link to password recovery that was mentioned in a form error (issue 652)
|
||||||
|
|
||||||
|
# InDefero 1.1 - Sun Mar 20 11:44 2011 UTC
|
||||||
|
|
||||||
|
## New Features
|
||||||
|
|
||||||
|
* _Version control_:
|
||||||
|
- Support for the monotone Version Control system (see [[InstallationScmMonotone]])
|
||||||
|
- Display detailed changeset information in the commit details (git, mtn) (issue 544)
|
||||||
|
- Show branch in the commit details (git, mtn, hg) (issue 450)
|
||||||
|
- Render branch and tag names in a popup and make them filterable (git, hg, mtn) (issue 601)
|
||||||
|
|
||||||
|
* _Issue tracking_:
|
||||||
|
- Forge-wide and per-project watch lists of starred issues (issue 589)
|
||||||
|
- Configure a default issue template for each project (issues 212 and 540)
|
||||||
|
- Pick default issue labels from the configured project settings (issue 556)
|
||||||
|
- Navigate to a preceding / following issue in the issue detail view
|
||||||
|
- Many new text syntaxes to auto-link revisions (see [[AutomaticLinks]], issue 569)
|
||||||
|
|
||||||
|
* _Documentation wiki_:
|
||||||
|
- Automatically create a table of contents on wiki pages (issue 350)
|
||||||
|
- Allow the usage of text labels for Wiki text links (issue 456)
|
||||||
|
|
||||||
|
* _Other_:
|
||||||
|
- Enhanced user profile page (issue 510)
|
||||||
|
- Manage multiple (commit) emails in the account settings (issues 136 and 500)
|
||||||
|
- Filter the timeline and its feed by item type (issue 543)
|
||||||
|
- Add multiple email addresses for project notifications (issue 372)
|
||||||
|
- Direct links to other projects via the new `Project List` dropdown
|
||||||
|
- InDefero gained a favicon (issue 594)
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
- Fix `Need SSH_ORIGINAL_COMMAND in environment` error for git sync (issue 198)
|
||||||
|
- Added an option to disable lengthy project size calculation in the forge (issue 403)
|
||||||
|
- Fix a problem when deleting an orphaned git repository (issue 467)
|
||||||
|
- Ignore XML parsing problems when trying to retrieve commit messages for svn (issues 469 and 518)
|
||||||
|
- Sort the project list by the display name of the project (issue 477)
|
||||||
|
- Project creation form now has a short description field as well (issue 479)
|
||||||
|
- Add more file extensions supported by our in-tree prettify version (issues 490 and 567)
|
||||||
|
- Improve the parsing of hg's log output (issues 507 and 508)
|
||||||
|
- Do not clean `<ins>` and `<del>` HTML markup from user input (issue 509)
|
||||||
|
- Improve HTML validation by switching from `strict` to `transitional` DOCTYPE (issue 511)
|
||||||
|
- Properly handle git commits without a changelog title (issue 520)
|
||||||
|
- Improve BSD compatibility in shell scripts (issue 526)
|
||||||
|
- Properly render inner whitespaces in viewed issue attachments (issue 528)
|
||||||
|
- Support for uploading SSH keys without optional comment (issue 531)
|
||||||
|
- Recognize irc: and git: protocols in Markdown renderer (issue 546)
|
||||||
|
- New config option `git_core_quotepath` to handle non-ASCII git file names (issue 553)
|
||||||
|
- Ensured that active views are rendered in the menu as such (issue 555)
|
||||||
|
- Add CSS for nested and mixed ordered and unordered lists (issue 557)
|
||||||
|
- Directories are now sorted before files in source tree views (issue 573)
|
||||||
|
- File attachments now have explicit view and download links in issue views (issue 575)
|
||||||
|
- Display anonymous access URL when user has no SSH key registered (issue 588)
|
||||||
|
- Improve the rendering of tag lists in issue views (issue 591)
|
||||||
|
- Improved error page when a commit or branch was not found (issue 609)
|
||||||
|
- Disable browser autocomplete of password fields in the account settings (issue 616)
|
||||||
|
- Improvements in the automatic linker parser (issue 618)
|
||||||
|
- The `createIssue` API method did not check the API authentication (issue 619)
|
||||||
|
- Reduce the memory footprint and compatibility of the internal diff parser (issues 627 and 633)
|
||||||
|
- Print the git branches and tags in bold which contain the currently displayed revision
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- Document how to contribute to Indefero in `CONTRIBUTE.mdtext` (issue 486)
|
||||||
|
- Note possible problems with mbstring.func_overload in `INSTALL.mdtext` (issue 481)
|
||||||
|
- Improve links to Markdown documentation (issue 489)
|
||||||
|
- Explain purpose of `idf_strong_key_check` in `idf.php-dist` (issue 516)
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
- Spanish translation added
|
||||||
|
- Started with a Simplified Chinese translation (issue 521)
|
||||||
|
- Started with a Russian translation
|
||||||
|
- Updates and fixes to the French translation (issue 574)
|
||||||
|
- Updates and fixes to the German translation
|
||||||
|
- English source language has been improved (issues 441, 478, and 631)
|
||||||
|
|
||||||
|
# InDefero 1.0 - Tue Apr 20 07:00 2010 UTC
|
||||||
|
|
||||||
|
First stable release.
|
||||||
|
|
173
logo/no_logo.svg
Normal file
173
logo/no_logo.svg
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
<?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"
|
||||||
|
sodipodi:docname="no_logo.svg"
|
||||||
|
inkscape:version="0.47 r22583"
|
||||||
|
id="svg2985"
|
||||||
|
height="32"
|
||||||
|
width="32"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:export-filename="/Users/tommyd/Entwicklung/indefero/www/media/idf/img/no_logo.png"
|
||||||
|
inkscape:export-xdpi="89.989998"
|
||||||
|
inkscape:export-ydpi="89.989998">
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1440"
|
||||||
|
inkscape:window-height="852"
|
||||||
|
id="namedview9"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="16.0625"
|
||||||
|
inkscape:cx="8.5507561"
|
||||||
|
inkscape:cy="16.122403"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="g2847"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true">
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="16,25.836575"
|
||||||
|
id="guide3752" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-18.677042,16"
|
||||||
|
id="guide3754" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs2987">
|
||||||
|
<inkscape:perspective
|
||||||
|
sodipodi:type="inkscape:persp3d"
|
||||||
|
inkscape:vp_x="0 : 16 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_z="32 : 16 : 1"
|
||||||
|
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||||
|
id="perspective13" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective2863"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3676"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3717"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="filter3816"
|
||||||
|
x="-0.14434362"
|
||||||
|
width="1.2886872"
|
||||||
|
y="-0.11562817"
|
||||||
|
height="1.2312563">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.1799243"
|
||||||
|
id="feGaussianBlur3818" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<metadata
|
||||||
|
id="metadata2990">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="shadow"
|
||||||
|
style="display:inline"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<g
|
||||||
|
transform="translate(0.44042901,0.78704792)"
|
||||||
|
id="g2847-8"
|
||||||
|
style="opacity:0.79710143;fill:#000000;stroke:#000000;stroke-opacity:1;filter:url(#filter3816)">
|
||||||
|
<g
|
||||||
|
id="g3838-0"
|
||||||
|
style="fill:#000000;stroke:#000000;stroke-opacity:1" />
|
||||||
|
<g
|
||||||
|
id="g2401-2"
|
||||||
|
transform="matrix(0.21219597,0,0,0.21219597,-70.751966,-27.73328)"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2.4000001;stroke-miterlimit:4;stroke-opacity:1;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-4"
|
||||||
|
d="m 396.19089,173.14471 c -7.67621,0.80661 -14.40195,5.39406 -19.58101,10.89131 -7.23597,7.88004 -11.69742,18.07908 -13.32198,28.60362 -1.7236,11.28173 -0.25925,23.20635 5.07686,33.37271 3.78607,7.24384 9.53161,13.92339 17.29701,16.96772 3.86478,1.53937 8.98362,1.03284 11.67912,-2.41036 2.64357,-3.5671 2.69463,-8.234 2.85756,-12.48867 0.045,-7.61054 -0.54749,-15.25544 0.45618,-22.83193 0.87131,-9.50623 4.03944,-18.56751 6.71612,-27.66851 1.16242,-4.44333 2.25094,-9.02808 1.97499,-13.64988 -0.48817,-4.62476 -3.58059,-9.31042 -8.2964,-10.4067 -1.57489,-0.44882 -3.23412,-0.48948 -4.85845,-0.37931 z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
id="path2391-8"
|
||||||
|
d="m 433.14691,149.28687 c 7.2059,2.76589 12.51512,8.93778 16.09494,15.58815 4.94991,9.48434 6.61962,20.49058 5.46486,31.07695 -1.25505,11.34342 -5.75582,22.48271 -13.54134,30.92159 -5.53192,6.01709 -12.81048,10.98198 -21.09918,11.91276 -4.13154,0.4866 -8.94486,-1.32748 -10.65734,-5.35104 -1.63027,-4.12976 -0.4717,-8.65084 0.47212,-12.80269 1.92628,-7.36287 4.47721,-14.59393 5.4687,-22.17201 1.61875,-9.40784 0.90381,-18.98034 0.67386,-28.46402 0.0272,-4.59278 0.1624,-9.30303 1.62515,-13.69592 1.66851,-4.34082 5.86829,-8.06645 10.70716,-7.90484 1.63738,-0.0259 3.25061,0.36424 4.79107,0.89107 z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer3"
|
||||||
|
inkscape:label="logo"
|
||||||
|
style="display:inline">
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-0.06540759,0.09444087)">
|
||||||
|
<g
|
||||||
|
id="g2847">
|
||||||
|
<g
|
||||||
|
id="g3838" />
|
||||||
|
<g
|
||||||
|
id="g2401"
|
||||||
|
transform="matrix(0.21219597,0,0,0.21219597,-70.751966,-27.73328)"
|
||||||
|
style="fill:#e6e6e6;fill-opacity:1;stroke:#a0a0a0;stroke-width:2.4000001;stroke-miterlimit:4;stroke-opacity:1;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 -7.67621,0.80661 -14.40195,5.39406 -19.58101,10.89131 -7.23597,7.88004 -11.69742,18.07908 -13.32198,28.60362 -1.7236,11.28173 -0.25925,23.20635 5.07686,33.37271 3.78607,7.24384 9.53161,13.92339 17.29701,16.96772 3.86478,1.53937 8.98362,1.03284 11.67912,-2.41036 2.64357,-3.5671 2.69463,-8.234 2.85756,-12.48867 0.045,-7.61054 -0.54749,-15.25544 0.45618,-22.83193 0.87131,-9.50623 4.03944,-18.56751 6.71612,-27.66851 1.16242,-4.44333 2.25094,-9.02808 1.97499,-13.64988 -0.48817,-4.62476 -3.58059,-9.31042 -8.2964,-10.4067 -1.57489,-0.44882 -3.23412,-0.48948 -4.85845,-0.37931 z"
|
||||||
|
style="fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:#a0a0a0;stroke-width:2.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
id="path2391"
|
||||||
|
d="m 433.14691,149.28687 c 7.2059,2.76589 12.51512,8.93778 16.09494,15.58815 4.94991,9.48434 6.61962,20.49058 5.46486,31.07695 -1.25505,11.34342 -5.75582,22.48271 -13.54134,30.92159 -5.53192,6.01709 -12.81048,10.98198 -21.09918,11.91276 -4.13154,0.4866 -8.94486,-1.32748 -10.65734,-5.35104 -1.63027,-4.12976 -0.4717,-8.65084 0.47212,-12.80269 1.92628,-7.36287 4.47721,-14.59393 5.4687,-22.17201 1.61875,-9.40784 0.90381,-18.98034 0.67386,-28.46402 0.0272,-4.59278 0.1624,-9.30303 1.62515,-13.69592 1.66851,-4.34082 5.86829,-8.06645 10.70716,-7.90484 1.63738,-0.0259 3.25061,0.36424 4.79107,0.89107 z"
|
||||||
|
style="fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:#a0a0a0;stroke-width:2.4000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.4 KiB |
27
phpunit.xml
Normal file
27
phpunit.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<phpunit backupGlobals="true"
|
||||||
|
backupStaticAttributes="false"
|
||||||
|
bootstrap="test/bootstrap.php"
|
||||||
|
convertErrorsToExceptions="true"
|
||||||
|
convertNoticesToExceptions="true"
|
||||||
|
convertWarningsToExceptions="true"
|
||||||
|
strict="false"
|
||||||
|
verbose="true">
|
||||||
|
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="Everything">
|
||||||
|
<directory>test/IDF/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist>
|
||||||
|
<directory suffix=".php">src/IDF</directory>
|
||||||
|
<exclude>
|
||||||
|
<directory suffix=".php">src/IDF/Tests</directory>
|
||||||
|
<directory suffix=".php">src/IDF/conf</directory>
|
||||||
|
<file>src/IDF/version.php</file>
|
||||||
|
</exclude>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
||||||
|
|
14
run-tests
Executable file
14
run-tests
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$xmlfile = dirname(__FILE__) .'/test/report.xml';
|
||||||
|
passthru('phpunit --coverage-clover='.$xmlfile);
|
||||||
|
$xml = simplexml_load_string(file_get_contents($xmlfile));
|
||||||
|
unlink($xmlfile);
|
||||||
|
printf(
|
||||||
|
'>>> code coverage %s/%s (%s%%)'."\n",
|
||||||
|
$xml->project->metrics['coveredstatements'],
|
||||||
|
$xml->project->metrics['statements'],
|
||||||
|
round(($xml->project->metrics['coveredstatements']/(float)$xml->project->metrics['statements']) * 100.0, 2)
|
||||||
|
);
|
||||||
|
|
@ -23,14 +23,17 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import commands
|
import subprocess
|
||||||
import traceback
|
|
||||||
|
SCRIPTDIR = os.path.abspath(__file__).rsplit(os.path.sep, 1)[0]
|
||||||
|
GITSERVEPHP = '%s/gitserve.php' % SCRIPTDIR
|
||||||
|
process = subprocess.Popen(['php', GITSERVEPHP, sys.argv[1]],
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
output = str.encode("\n").join(process.communicate()).strip()
|
||||||
|
status = process.wait()
|
||||||
|
|
||||||
n = len("/gitserve.py")
|
|
||||||
GITSERVEPHP = '%s/gitserve.php' % traceback.extract_stack(limit=1)[0][0][0:-n]
|
|
||||||
status, output = commands.getstatusoutput('php %s %s' % (GITSERVEPHP, sys.argv[1]))
|
|
||||||
if status == 0:
|
if status == 0:
|
||||||
os.execvp('git', ['git', 'shell', '-c', output.strip()])
|
os.execvp('git', ['git', 'shell', '-c', output.strip()])
|
||||||
else:
|
else:
|
||||||
sys.stderr.write("%s\n" % output)
|
sys.stderr.write("%s\n" % output.strip())
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
207
src/IDF/Diff.php
207
src/IDF/Diff.php
@ -27,17 +27,17 @@
|
|||||||
*/
|
*/
|
||||||
class IDF_Diff
|
class IDF_Diff
|
||||||
{
|
{
|
||||||
public $repo = '';
|
public $path_strip_level = 0;
|
||||||
public $diff = '';
|
|
||||||
protected $lines = array();
|
protected $lines = array();
|
||||||
|
|
||||||
public $files = array();
|
public $files = array();
|
||||||
|
|
||||||
public function __construct($diff, $repo='')
|
public function __construct($diff, $path_strip_level = 0)
|
||||||
{
|
{
|
||||||
$this->repo = $repo;
|
$this->path_strip_level = $path_strip_level;
|
||||||
$this->diff = $diff;
|
// this works because in unified diff format even empty lines are
|
||||||
$this->lines = preg_split("/\015\012|\015|\012/", $diff);
|
// either prefixed with a '+', '-' or ' '
|
||||||
|
$this->lines = preg_split("/\015\012|\015|\012/", $diff, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function parse()
|
public function parse()
|
||||||
@ -49,118 +49,95 @@ class IDF_Diff
|
|||||||
$files = array();
|
$files = array();
|
||||||
$indiff = false; // Used to skip the headers in the git patches
|
$indiff = false; // Used to skip the headers in the git patches
|
||||||
$i = 0; // Used to skip the end of a git patch with --\nversion number
|
$i = 0; // Used to skip the end of a git patch with --\nversion number
|
||||||
foreach ($this->lines as $line) {
|
$diffsize = count($this->lines);
|
||||||
$i++;
|
while ($i < $diffsize) {
|
||||||
if (0 === strpos($line, '--') and isset($this->lines[$i])
|
// look for the potential beginning of a diff
|
||||||
and preg_match('/^\d+\.\d+\.\d+\.\d+$/', $this->lines[$i])) {
|
if (substr($this->lines[$i], 0, 4) !== '--- ') {
|
||||||
break;
|
$i++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (0 === strpos($line, 'diff --git a')) {
|
|
||||||
$current_file = self::getFile($line);
|
// we're inside a diff candiate
|
||||||
$files[$current_file] = array();
|
$oldfileline = $this->lines[$i++];
|
||||||
$files[$current_file]['chunks'] = array();
|
$newfileline = $this->lines[$i++];
|
||||||
$files[$current_file]['chunks_def'] = array();
|
if (substr($newfileline, 0, 4) !== '+++ ') {
|
||||||
$current_chunk = 0;
|
// not a valid diff here, move on
|
||||||
$indiff = true;
|
|
||||||
continue;
|
continue;
|
||||||
} else if (preg_match('#^diff -r [^\s]+ -r [^\s]+ (.+)$#', $line, $matches)) {
|
}
|
||||||
$current_file = $matches[1];
|
|
||||||
$files[$current_file] = array();
|
// use new file name by default
|
||||||
$files[$current_file]['chunks'] = array();
|
preg_match("/^\+\+\+ ([^\t]+)/", $newfileline, $m);
|
||||||
$files[$current_file]['chunks_def'] = array();
|
$current_file = $m[1];
|
||||||
$current_chunk = 0;
|
if ($current_file === '/dev/null') {
|
||||||
$indiff = true;
|
// except if it's /dev/null, use the old one instead
|
||||||
continue;
|
// eg. mtn 0.48 and newer
|
||||||
} else if (!$indiff && 0 === strpos($line, '=========')) {
|
preg_match("/^--- ([^\t]+)/", $oldfileline, $m);
|
||||||
// ignore pseudo stanzas with a hint of a binary file
|
$current_file = $m[1];
|
||||||
if (preg_match("/^# (.+) is binary/", $this->lines[$i]))
|
}
|
||||||
continue;
|
if ($this->path_strip_level > 0) {
|
||||||
// by default always use the new name of a possibly renamed file
|
$fileparts = explode('/', $current_file, $this->path_strip_level+1);
|
||||||
$current_file = self::getMtnFile($this->lines[$i+1]);
|
$current_file = array_pop($fileparts);
|
||||||
// mtn 0.48 and newer set /dev/null as file path for dropped files
|
}
|
||||||
// so we display the old name here
|
$current_chunk = 0;
|
||||||
if ($current_file == "/dev/null") {
|
$files[$current_file] = array();
|
||||||
$current_file = self::getMtnFile($this->lines[$i]);
|
$files[$current_file]['chunks'] = array();
|
||||||
|
$files[$current_file]['chunks_def'] = array();
|
||||||
|
|
||||||
|
while ($i < $diffsize && substr($this->lines[$i], 0, 3) === '@@ ') {
|
||||||
|
$elems = preg_match('/@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@.*/',
|
||||||
|
$this->lines[$i++], $results);
|
||||||
|
if ($elems != 1) {
|
||||||
|
// hunk is badly formatted
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if ($current_file == "/dev/null") {
|
$delstart = $results[1];
|
||||||
throw new Exception(
|
$dellines = $results[2] === '' ? 1 : $results[2];
|
||||||
"could not determine path from diff"
|
$addstart = $results[3];
|
||||||
);
|
$addlines = $results[4] === '' ? 1 : $results[4];
|
||||||
}
|
|
||||||
$files[$current_file] = array();
|
$files[$current_file]['chunks_def'][] = array(
|
||||||
$files[$current_file]['chunks'] = array();
|
array($delstart, $dellines), array($addstart, $addlines)
|
||||||
$files[$current_file]['chunks_def'] = array();
|
);
|
||||||
$current_chunk = 0;
|
|
||||||
$indiff = true;
|
|
||||||
continue;
|
|
||||||
} else 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;
|
|
||||||
$indiff = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!$indiff) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (0 === strpos($line, '@@ ')) {
|
|
||||||
$files[$current_file]['chunks_def'][] = self::getChunk($line);
|
|
||||||
$files[$current_file]['chunks'][] = array();
|
$files[$current_file]['chunks'][] = array();
|
||||||
|
|
||||||
|
while ($i < $diffsize && ($addlines >= 0 || $dellines >= 0)) {
|
||||||
|
$linetype = $this->lines[$i] != '' ? $this->lines[$i][0] : ' ';
|
||||||
|
switch ($linetype) {
|
||||||
|
case ' ':
|
||||||
|
$files[$current_file]['chunks'][$current_chunk][] =
|
||||||
|
array($delstart, $addstart, substr($this->lines[$i++], 1));
|
||||||
|
$dellines--;
|
||||||
|
$addlines--;
|
||||||
|
$delstart++;
|
||||||
|
$addstart++;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
$files[$current_file]['chunks'][$current_chunk][] =
|
||||||
|
array('', $addstart, substr($this->lines[$i++], 1));
|
||||||
|
$addlines--;
|
||||||
|
$addstart++;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
$files[$current_file]['chunks'][$current_chunk][] =
|
||||||
|
array($delstart, '', substr($this->lines[$i++], 1));
|
||||||
|
$dellines--;
|
||||||
|
$delstart++;
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
// ignore newline handling for now, see issue 636
|
||||||
|
$i++;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
$current_chunk++;
|
$current_chunk++;
|
||||||
$lline = $files[$current_file]['chunks_def'][$current_chunk-1][0][0];
|
|
||||||
$rline = $files[$current_file]['chunks_def'][$current_chunk-1][1][0];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (0 === strpos($line, '---') or 0 === strpos($line, '+++')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (0 === strpos($line, '-')) {
|
|
||||||
$files[$current_file]['chunks'][$current_chunk-1][] = array($lline, '', substr($line, 1));
|
|
||||||
$lline++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (0 === strpos($line, '+')) {
|
|
||||||
$files[$current_file]['chunks'][$current_chunk-1][] = array('', $rline, substr($line, 1));
|
|
||||||
$rline++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (0 === strpos($line, ' ')) {
|
|
||||||
$files[$current_file]['chunks'][$current_chunk-1][] = array($lline, $rline, substr($line, 1));
|
|
||||||
$rline++;
|
|
||||||
$lline++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($line == '') {
|
|
||||||
$files[$current_file]['chunks'][$current_chunk-1][] = array($lline, $rline, $line);
|
|
||||||
$rline++;
|
|
||||||
$lline++;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->files = $files;
|
$this->files = $files;
|
||||||
return $files;
|
return $files;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getFile($line)
|
|
||||||
{
|
|
||||||
$line = substr(trim($line), 10);
|
|
||||||
$n = (int) strlen($line)/2;
|
|
||||||
return trim(substr($line, 3, $n-3));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getSvnFile($line)
|
|
||||||
{
|
|
||||||
return substr(trim($line), 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getMtnFile($line)
|
|
||||||
{
|
|
||||||
preg_match("/^[+-]{3} ([^\t]+)/", $line, $m);
|
|
||||||
return $m[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the html version of a parsed diff.
|
* Return the html version of a parsed diff.
|
||||||
*/
|
*/
|
||||||
@ -197,7 +174,6 @@ class IDF_Diff
|
|||||||
return Pluf_Template::markSafe($out);
|
return Pluf_Template::markSafe($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function padLine($line)
|
public static function padLine($line)
|
||||||
{
|
{
|
||||||
$line = str_replace("\t", ' ', $line);
|
$line = str_replace("\t", ' ', $line);
|
||||||
@ -210,19 +186,6 @@ class IDF_Diff
|
|||||||
return str_repeat(' ', $i).substr($line, $i);
|
return str_repeat(' ', $i).substr($line, $i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array array(array(start, n), array(start, n))
|
|
||||||
*/
|
|
||||||
public static function getChunk($line)
|
|
||||||
{
|
|
||||||
$elts = explode(' ', $line);
|
|
||||||
$res = array();
|
|
||||||
for ($i=1;$i<3;$i++) {
|
|
||||||
$res[] = explode(',', trim(substr($elts[$i], 1)));
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Review patch.
|
* Review patch.
|
||||||
*
|
*
|
||||||
@ -347,7 +310,6 @@ class IDF_Diff
|
|||||||
return $nnew_chunks;
|
return $nnew_chunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function renderCompared($chunks, $filename)
|
public function renderCompared($chunks, $filename)
|
||||||
{
|
{
|
||||||
$fileinfo = IDF_FileUtil::getMimeType($filename);
|
$fileinfo = IDF_FileUtil::getMimeType($filename);
|
||||||
@ -381,6 +343,5 @@ class IDF_Diff
|
|||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
return Pluf_Template::markSafe($out);
|
return Pluf_Template::markSafe($out);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
96
src/IDF/EmailAddress.php
Normal file
96
src/IDF/EmailAddress.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?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 Email addresses
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class IDF_EmailAddress extends Pluf_Model
|
||||||
|
{
|
||||||
|
public $_model = __CLASS__;
|
||||||
|
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
$this->_a['table'] = 'idf_emailaddresses';
|
||||||
|
$this->_a['model'] = __CLASS__;
|
||||||
|
$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,
|
||||||
|
),
|
||||||
|
'user' =>
|
||||||
|
array(
|
||||||
|
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||||
|
'model' => 'Pluf_User',
|
||||||
|
'blank' => false,
|
||||||
|
'verbose' => __('user'),
|
||||||
|
),
|
||||||
|
'address' =>
|
||||||
|
array(
|
||||||
|
'type' => 'Pluf_DB_Field_Email',
|
||||||
|
'blank' => false,
|
||||||
|
'verbose' => __('email'),
|
||||||
|
'unique' => true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// WARNING: Not using getSqlTable on the Pluf_User object to
|
||||||
|
// avoid recursion.
|
||||||
|
$t_users = $this->_con->pfx.'users';
|
||||||
|
$this->_a['views'] = array(
|
||||||
|
'join_user' =>
|
||||||
|
array(
|
||||||
|
'join' => 'LEFT JOIN '.$t_users
|
||||||
|
.' ON '.$t_users.'.id='.$this->_con->qn('user'),
|
||||||
|
'select' => $this->getSelect().', '
|
||||||
|
.$t_users.'.login AS login',
|
||||||
|
'props' => array('login' => 'login'),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_email_addresses_for_user($user)
|
||||||
|
{
|
||||||
|
$addr = $user->get_idf_emailaddress_list();
|
||||||
|
$addr[] = (object)array("address" => $user->email, "id" => -1, "user" => $user);
|
||||||
|
return $addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_user_for_email_address($email)
|
||||||
|
{
|
||||||
|
$sql = new Pluf_SQL('email=%s', array($email));
|
||||||
|
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||||
|
if ($users->count() > 0) {
|
||||||
|
return $users[0];
|
||||||
|
}
|
||||||
|
$sql = new Pluf_SQL('address=%s', array($email));
|
||||||
|
$matches = Pluf::factory('IDF_EmailAddress')->getList(array('filter'=>$sql->gen()));
|
||||||
|
if ($matches->count() > 0) {
|
||||||
|
return new Pluf_User($matches[0]->user);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -182,7 +182,7 @@ class IDF_Form_Admin_ProjectCreate extends Pluf_Form
|
|||||||
// we accept only starting with http(s):// to avoid people
|
// we accept only starting with http(s):// to avoid people
|
||||||
// trying to access the local filesystem.
|
// trying to access the local filesystem.
|
||||||
if (!preg_match('#^(http|https)://#', $url)) {
|
if (!preg_match('#^(http|https)://#', $url)) {
|
||||||
throw new Pluf_Form_Invalid(__('Only a remote repository available throught http or https are allowed. For example "http://somewhere.com/svn/trunk".'));
|
throw new Pluf_Form_Invalid(__('Only a remote repository available through HTTP or HTTPS is allowed. For example "http://somewhere.com/svn/trunk".'));
|
||||||
}
|
}
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ class IDF_Form_Admin_ProjectUpdate extends Pluf_Form
|
|||||||
$mtn_master_branch)) {
|
$mtn_master_branch)) {
|
||||||
throw new Pluf_Form_Invalid(__(
|
throw new Pluf_Form_Invalid(__(
|
||||||
'The master branch is empty or contains illegal characters, '.
|
'The master branch is empty or contains illegal characters, '.
|
||||||
'please use only letters, digits, dashs and dots as separators.'
|
'please use only letters, digits, dashes and dots as separators.'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ class IDF_Form_Admin_UserCreate extends Pluf_Form
|
|||||||
array('required' => true,
|
array('required' => true,
|
||||||
'label' => __('Email'),
|
'label' => __('Email'),
|
||||||
'initial' => '',
|
'initial' => '',
|
||||||
'help_text' => __('Double check the email address as the password is directly sent to the user.'),
|
'help_text' => __('Double check the email address as the password is sent directly to the user.'),
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->fields['language'] = new Pluf_Form_Field_Varchar(
|
$this->fields['language'] = new Pluf_Form_Field_Varchar(
|
||||||
|
@ -78,7 +78,7 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
|
|||||||
'label' => __('Password'),
|
'label' => __('Password'),
|
||||||
'initial' => '',
|
'initial' => '',
|
||||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||||
'help_text' => Pluf_Template::markSafe(__('Leave blank if you do not want to change the password.').'<br />'.__('The password must be hard for other people to find it, but easy for the user to remember.')),
|
'help_text' => Pluf_Template::markSafe(__('Leave blank if you do not want to change the password.').'<br />'.__('The password must be hard for other people to guess, but easy for the user to remember.')),
|
||||||
'widget_attrs' => array(
|
'widget_attrs' => array(
|
||||||
'maxlength' => 50,
|
'maxlength' => 50,
|
||||||
'size' => 15,
|
'size' => 15,
|
||||||
@ -161,7 +161,7 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
|
|||||||
'label' => __('Staff'),
|
'label' => __('Staff'),
|
||||||
'initial' => $this->user->staff,
|
'initial' => $this->user->staff,
|
||||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||||
'help_text' => __('If you give staff rights to a user, you really need to trust him.'),
|
'help_text' => __('If you give staff rights to a user, you really need to trust them.'),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +173,7 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
|
|||||||
'initial' => $this->user->active,
|
'initial' => $this->user->active,
|
||||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||||
'widget_attrs' => $attrs,
|
'widget_attrs' => $attrs,
|
||||||
'help_text' => __('If the user is not getting the confirmation email or is abusing the system, you can directly enable or disable his account here.'),
|
'help_text' => __('If the user is not getting the confirmation email or is abusing the system, you can directly enable or disable their account here.'),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ Maintainability = Hinders future changes';
|
|||||||
{
|
{
|
||||||
$this->fields['labels_issue_template'] = new Pluf_Form_Field_Varchar(
|
$this->fields['labels_issue_template'] = new Pluf_Form_Field_Varchar(
|
||||||
array('required' => false,
|
array('required' => false,
|
||||||
'label' => __('Define an issue template to hint the reporter to provide certain information'),
|
'label' => __('Define an issue template to hint to the reporter to provide certain information'),
|
||||||
'initial' => self::init_template,
|
'initial' => self::init_template,
|
||||||
'widget_attrs' => array('rows' => 7,
|
'widget_attrs' => array('rows' => 7,
|
||||||
'cols' => 75),
|
'cols' => 75),
|
||||||
|
@ -86,7 +86,7 @@ class IDF_Form_Password extends Pluf_Form
|
|||||||
$return_url = Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryInputCode');
|
$return_url = Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryInputCode');
|
||||||
$tmpl = new Pluf_Template('idf/user/passrecovery-email.txt');
|
$tmpl = new Pluf_Template('idf/user/passrecovery-email.txt');
|
||||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||||
$code = trim($cr->encrypt($user->email.':'.$user->id.':'.time()),
|
$code = trim($cr->encrypt($user->email.':'.$user->id.':'.time().':primary'),
|
||||||
'~');
|
'~');
|
||||||
$code = substr(md5(Pluf::f('secret_key').$code), 0, 2).$code;
|
$code = substr(md5(Pluf::f('secret_key').$code), 0, 2).$code;
|
||||||
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecovery', array($code), array(), false);
|
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecovery', array($code), array(), false);
|
||||||
|
140
src/IDF/Form/ProjectConf.php
Normal file
140
src/IDF/Form/ProjectConf.php
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# This file is part of InDefero, an open source project management application.
|
||||||
|
# Copyright(C) 2008-2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
#(at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration of the project.
|
||||||
|
*/
|
||||||
|
class IDF_Form_ProjectConf extends Pluf_Form
|
||||||
|
{
|
||||||
|
public $project = null;
|
||||||
|
|
||||||
|
public function initFields($extra=array())
|
||||||
|
{
|
||||||
|
$this->project = $extra['project'];
|
||||||
|
|
||||||
|
// Basic part
|
||||||
|
$this->fields['name'] = new Pluf_Form_Field_Varchar(array('required' => true,
|
||||||
|
'label' => __('Name'),
|
||||||
|
'initial' => $this->project->name,
|
||||||
|
));
|
||||||
|
$this->fields['shortdesc'] = new Pluf_Form_Field_Varchar(array('required' => true,
|
||||||
|
'label' => __('Short Description'),
|
||||||
|
'initial' => $this->project->shortdesc,
|
||||||
|
'widget_attrs' => array('size' => '68'),
|
||||||
|
));
|
||||||
|
$this->fields['description'] = new Pluf_Form_Field_Varchar(array('required' => true,
|
||||||
|
'label' => __('Description'),
|
||||||
|
'initial' => $this->project->description,
|
||||||
|
'widget_attrs' => array('cols' => 68,
|
||||||
|
'rows' => 26,
|
||||||
|
),
|
||||||
|
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Logo part
|
||||||
|
$upload_path = Pluf::f('upload_path', false);
|
||||||
|
if (false === $upload_path) {
|
||||||
|
throw new Pluf_Exception_SettingError(__('The "upload_path" configuration variable was not set.'));
|
||||||
|
}
|
||||||
|
$upload_path .= '/' . $this->project->shortname;
|
||||||
|
$filename = '/%s';
|
||||||
|
$this->fields['logo'] = new Pluf_Form_Field_File(array('required' => false,
|
||||||
|
'label' => __('Update the logo'),
|
||||||
|
'initial' => '',
|
||||||
|
'help_text' => __('The logo must be a picture with a size of 32 by 32.'),
|
||||||
|
'max_size' => Pluf::f('max_upload_size', 5 * 1024),
|
||||||
|
'move_function_params' =>
|
||||||
|
array('upload_path' => $upload_path,
|
||||||
|
'upload_path_create' => true,
|
||||||
|
'file_name' => $filename,
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->fields['logo_remove'] = new Pluf_Form_Field_Boolean(array('required' => false,
|
||||||
|
'label' => __('Remove the current logo'),
|
||||||
|
'initial' => false,
|
||||||
|
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we have uploaded a file, but the form failed remove it.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function failed()
|
||||||
|
{
|
||||||
|
if (!empty($this->cleaned_data['logo'])
|
||||||
|
&& file_exists(Pluf::f('upload_path').'/'.$this->cleaned_data['logo'])) {
|
||||||
|
unlink(Pluf::f('upload_path').'/'.$this->cleaned_data['logo']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clean()
|
||||||
|
{
|
||||||
|
if (!isset($this->cleaned_data['logo_remove'])) {
|
||||||
|
$this->cleaned_data['logo_remove'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->cleaned_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clean_logo()
|
||||||
|
{
|
||||||
|
if (empty($this->cleaned_data['logo'])) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$meta = getimagesize(Pluf::f('upload_path') . '/' . $this->project->shortname . $this->cleaned_data['logo']);
|
||||||
|
|
||||||
|
if ($meta === false) {
|
||||||
|
throw new Pluf_Form_Invalid("Could not determine the size of the uploaded picture.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($meta[0] !== 32 || $meta[1] !== 32) {
|
||||||
|
throw new Pluf_Form_Invalid("The picture must have a size of 32 by 32.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->cleaned_data['logo'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save($commit=true)
|
||||||
|
{
|
||||||
|
$conf = $this->project->getConf();
|
||||||
|
|
||||||
|
// Basic part
|
||||||
|
$this->project->name = $this->cleaned_data['name'];
|
||||||
|
$this->project->shortdesc = $this->cleaned_data['shortdesc'];
|
||||||
|
$this->project->description = $this->cleaned_data['description'];
|
||||||
|
$this->project->update();
|
||||||
|
|
||||||
|
// Logo part
|
||||||
|
if ($this->cleaned_data['logo'] !== "") {
|
||||||
|
$conf->setVal('logo', $this->cleaned_data['logo']);
|
||||||
|
}
|
||||||
|
if ($this->cleaned_data['logo_remove'] === true) {
|
||||||
|
@unlink(Pluf::f('upload_path') . '/' . $this->project->shortname . $conf->getVal('logo'));
|
||||||
|
$conf->delVal('logo');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -42,7 +42,7 @@ class IDF_Form_Register extends Pluf_Form
|
|||||||
'max_length' => 15,
|
'max_length' => 15,
|
||||||
'min_length' => 3,
|
'min_length' => 3,
|
||||||
'initial' => $login,
|
'initial' => $login,
|
||||||
'help_text' => __('The login must be between 3 and 15 characters long and contains only letters and digits.'),
|
'help_text' => __('The login must be between 3 and 15 characters long and contain only letters and digits.'),
|
||||||
'widget_attrs' => array(
|
'widget_attrs' => array(
|
||||||
'maxlength' => 15,
|
'maxlength' => 15,
|
||||||
'size' => 10,
|
'size' => 10,
|
||||||
@ -52,7 +52,7 @@ class IDF_Form_Register extends Pluf_Form
|
|||||||
array('required' => true,
|
array('required' => true,
|
||||||
'label' => __('Your email'),
|
'label' => __('Your email'),
|
||||||
'initial' => '',
|
'initial' => '',
|
||||||
'help_text' => __('We will never send you any unsolicited emails. We hate spams too!'),
|
'help_text' => __('We will never send you any unsolicited emails. We hate spam too!'),
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->fields['terms'] = new Pluf_Form_Field_Boolean(
|
$this->fields['terms'] = new Pluf_Form_Field_Boolean(
|
||||||
@ -93,10 +93,8 @@ class IDF_Form_Register extends Pluf_Form
|
|||||||
function clean_email()
|
function clean_email()
|
||||||
{
|
{
|
||||||
$this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email']));
|
$this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email']));
|
||||||
$guser = new Pluf_User();
|
if (Pluf::factory('IDF_EmailAddress')->get_user_for_email_address($this->cleaned_data['email']) != null) {
|
||||||
$sql = new Pluf_SQL('email=%s', $this->cleaned_data['email']);
|
throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used. If you need to, click on the help link to recover your password.'), $this->cleaned_data['email']));
|
||||||
if ($guser->getCount(array('filter' => $sql->gen())) > 0) {
|
|
||||||
throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used. If you need, click on the help link to recover your password.'), $this->cleaned_data['email']));
|
|
||||||
}
|
}
|
||||||
return $this->cleaned_data['email'];
|
return $this->cleaned_data['email'];
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ class IDF_Form_RegisterConfirmation extends Pluf_Form
|
|||||||
'label' => __('Your password'),
|
'label' => __('Your password'),
|
||||||
'initial' => '',
|
'initial' => '',
|
||||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||||
'help_text' => __('Your password must be hard for other people to find it, but easy for you to remember.'),
|
'help_text' => __('Your password must be hard for other people to guess, but easy for you to remember.'),
|
||||||
'widget_attrs' => array(
|
'widget_attrs' => array(
|
||||||
'maxlength' => 50,
|
'maxlength' => 50,
|
||||||
'size' => 15,
|
'size' => 15,
|
||||||
|
@ -52,7 +52,7 @@ class IDF_Form_ReviewFileComment extends Pluf_Form
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||||
array('required' => false,
|
array('required' => true,
|
||||||
'label' => __('General comment'),
|
'label' => __('General comment'),
|
||||||
'initial' => '',
|
'initial' => '',
|
||||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||||
@ -64,6 +64,8 @@ class IDF_Form_ReviewFileComment extends Pluf_Form
|
|||||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||||
$this->show_full = true;
|
$this->show_full = true;
|
||||||
|
} else {
|
||||||
|
$this->show_full = false;
|
||||||
}
|
}
|
||||||
if ($this->show_full) {
|
if ($this->show_full) {
|
||||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||||
@ -94,40 +96,24 @@ class IDF_Form_ReviewFileComment extends Pluf_Form
|
|||||||
*/
|
*/
|
||||||
public function clean()
|
public function clean()
|
||||||
{
|
{
|
||||||
$isOk = false;
|
foreach ($this->files as $filename => $def) {
|
||||||
|
if (!empty($this->cleaned_data[md5($filename)])) {
|
||||||
foreach($this->files as $filename => $def) {
|
return $this->cleaned_data;
|
||||||
$this->cleaned_data[md5($filename)] = trim($this->cleaned_data[md5($filename)]);
|
|
||||||
if(!empty($this->cleaned_data[md5($filename)])) {
|
|
||||||
$isOk = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw new Pluf_Form_Invalid(__('You need to provide comments on at least one file.'));
|
||||||
if(!empty($this->cleaned_data['content'])) {
|
|
||||||
$isOk = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$isOk) {
|
|
||||||
throw new Pluf_Form_Invalid(__('You need to provide your general comment about the proposal, or comments on at least one file.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->cleaned_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function clean_content()
|
function clean_content()
|
||||||
{
|
{
|
||||||
$content = trim($this->cleaned_data['content']);
|
$content = trim($this->cleaned_data['content']);
|
||||||
if(empty($content)) {
|
if (!$this->show_full and strlen($content) == 0) {
|
||||||
if ($this->fields['status']->initial != $this->fields['status']->value) {
|
throw new Pluf_Form_Invalid(__('You need to provide your general comment about the proposal.'));
|
||||||
return __('The status have been updated.');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return $content;
|
|
||||||
}
|
}
|
||||||
|
return $content;
|
||||||
throw new Pluf_Form_Invalid(__('This field is required.'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the model in the database.
|
* Save the model in the database.
|
||||||
*
|
*
|
||||||
|
@ -83,7 +83,7 @@ class IDF_Form_Upload extends Pluf_Form
|
|||||||
if (strlen($extra)) $extra .= '|';
|
if (strlen($extra)) $extra .= '|';
|
||||||
if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $this->cleaned_data['file'])) {
|
if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $this->cleaned_data['file'])) {
|
||||||
@unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']);
|
@unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']);
|
||||||
throw new Pluf_Form_Invalid(__('For security reason, you cannot upload a file with this extension.'));
|
throw new Pluf_Form_Invalid(__('For security reasons, you cannot upload a file with this extension.'));
|
||||||
}
|
}
|
||||||
return $this->cleaned_data['file'];
|
return $this->cleaned_data['file'];
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,7 @@ class IDF_Form_UserAccount extends Pluf_Form
|
|||||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
'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.')),
|
'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(
|
'widget_attrs' => array(
|
||||||
|
'autocomplete' => 'off',
|
||||||
'maxlength' => 50,
|
'maxlength' => 50,
|
||||||
'size' => 15,
|
'size' => 15,
|
||||||
),
|
),
|
||||||
@ -89,6 +90,7 @@ class IDF_Form_UserAccount extends Pluf_Form
|
|||||||
'initial' => '',
|
'initial' => '',
|
||||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||||
'widget_attrs' => array(
|
'widget_attrs' => array(
|
||||||
|
'autocomplete' => 'off',
|
||||||
'maxlength' => 50,
|
'maxlength' => 50,
|
||||||
'size' => 15,
|
'size' => 15,
|
||||||
),
|
),
|
||||||
@ -161,8 +163,44 @@ class IDF_Form_UserAccount extends Pluf_Form
|
|||||||
'widget_attrs' => array('rows' => 3,
|
'widget_attrs' => array('rows' => 3,
|
||||||
'cols' => 40),
|
'cols' => 40),
|
||||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||||
'help_text' => __('Paste a SSH or monotone public key. Be careful to not provide your private key here!')
|
'help_text' => __('Paste an SSH or monotone public key. Be careful to not provide your private key here!')
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$this->fields['secondary_mail'] = new Pluf_Form_Field_Email(
|
||||||
|
array('required' => false,
|
||||||
|
'label' => __('Add a secondary mail address'),
|
||||||
|
'initial' => '',
|
||||||
|
'help_text' => __('You will get a mail to confirm that you own the address you specify.'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function send_validation_mail($new_email, $secondary_mail=false)
|
||||||
|
{
|
||||||
|
if ($secondary_mail) {
|
||||||
|
$type = "secondary";
|
||||||
|
} else {
|
||||||
|
$type = "primary";
|
||||||
|
}
|
||||||
|
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||||
|
$encrypted = trim($cr->encrypt($new_email.':'.$this->user->id.':'.time().':'.$type), '~');
|
||||||
|
$key = substr(md5(Pluf::f('secret_key').$encrypted), 0, 2).$encrypted;
|
||||||
|
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailDo', array($key), array(), false);
|
||||||
|
$urlik = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailInputKey', array(), array(), false);
|
||||||
|
$context = new Pluf_Template_Context(
|
||||||
|
array('key' => Pluf_Template::markSafe($key),
|
||||||
|
'url' => Pluf_Template::markSafe($url),
|
||||||
|
'urlik' => Pluf_Template::markSafe($urlik),
|
||||||
|
'email' => $new_email,
|
||||||
|
'user'=> $this->user,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$tmpl = new Pluf_Template('idf/user/changeemail-email.txt');
|
||||||
|
$text_email = $tmpl->render($context);
|
||||||
|
$email = new Pluf_Mail(Pluf::f('from_email'), $new_email,
|
||||||
|
__('Confirm your new email address.'));
|
||||||
|
$email->addTextMessage($text_email);
|
||||||
|
$email->sendMail();
|
||||||
|
$this->user->setMessage(sprintf(__('A validation email has been sent to "%s" to validate the email address change.'), Pluf_esc($new_email)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -188,26 +226,7 @@ class IDF_Form_UserAccount extends Pluf_Form
|
|||||||
$new_email = $this->cleaned_data['email'];
|
$new_email = $this->cleaned_data['email'];
|
||||||
unset($this->cleaned_data['email']);
|
unset($this->cleaned_data['email']);
|
||||||
if ($old_email != $new_email) {
|
if ($old_email != $new_email) {
|
||||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
$this->send_validation_mail($new_email);
|
||||||
$encrypted = trim($cr->encrypt($new_email.':'.$this->user->id.':'.time()), '~');
|
|
||||||
$key = substr(md5(Pluf::f('secret_key').$encrypted), 0, 2).$encrypted;
|
|
||||||
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailDo', array($key), array(), false);
|
|
||||||
$urlik = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailInputKey', array(), array(), false);
|
|
||||||
$context = new Pluf_Template_Context(
|
|
||||||
array('key' => Pluf_Template::markSafe($key),
|
|
||||||
'url' => Pluf_Template::markSafe($url),
|
|
||||||
'urlik' => Pluf_Template::markSafe($urlik),
|
|
||||||
'email' => $new_email,
|
|
||||||
'user'=> $this->user,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$tmpl = new Pluf_Template('idf/user/changeemail-email.txt');
|
|
||||||
$text_email = $tmpl->render($context);
|
|
||||||
$email = new Pluf_Mail(Pluf::f('from_email'), $new_email,
|
|
||||||
__('Confirm your new email address.'));
|
|
||||||
$email->addTextMessage($text_email);
|
|
||||||
$email->sendMail();
|
|
||||||
$this->user->setMessage(sprintf(__('A validation email has been sent to "%s" to validate the email address change.'), Pluf_esc($new_email)));
|
|
||||||
}
|
}
|
||||||
$this->user->setFromFormData($this->cleaned_data);
|
$this->user->setFromFormData($this->cleaned_data);
|
||||||
// Add key as needed.
|
// Add key as needed.
|
||||||
@ -219,6 +238,9 @@ class IDF_Form_UserAccount extends Pluf_Form
|
|||||||
$key->create();
|
$key->create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ('' !== $this->cleaned_data['secondary_mail']) {
|
||||||
|
$this->send_validation_mail($this->cleaned_data['secondary_mail'], true);
|
||||||
|
}
|
||||||
|
|
||||||
if ($commit) {
|
if ($commit) {
|
||||||
$this->user->update();
|
$this->user->update();
|
||||||
@ -337,7 +359,7 @@ class IDF_Form_UserAccount extends Pluf_Form
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Pluf_Form_Invalid(
|
throw new Pluf_Form_Invalid(
|
||||||
__('Public key looks neither like a SSH '.
|
__('Public key looks like neither an SSH '.
|
||||||
'nor monotone public key.'));
|
'nor monotone public key.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,15 +415,22 @@ class IDF_Form_UserAccount extends Pluf_Form
|
|||||||
function clean_email()
|
function clean_email()
|
||||||
{
|
{
|
||||||
$this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email']));
|
$this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email']));
|
||||||
$guser = new Pluf_User();
|
$user = Pluf::factory('IDF_EmailAddress')->get_user_for_email_address($this->cleaned_data['email']);
|
||||||
$sql = new Pluf_SQL('email=%s AND id!=%s',
|
if ($user != null and $user->id != $this->user->id) {
|
||||||
array($this->cleaned_data['email'], $this->user->id));
|
|
||||||
if ($guser->getCount(array('filter' => $sql->gen())) > 0) {
|
|
||||||
throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used.'), $this->cleaned_data['email']));
|
throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used.'), $this->cleaned_data['email']));
|
||||||
}
|
}
|
||||||
return $this->cleaned_data['email'];
|
return $this->cleaned_data['email'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clean_secondary_mail()
|
||||||
|
{
|
||||||
|
$this->cleaned_data['secondary_mail'] = mb_strtolower(trim($this->cleaned_data['secondary_mail']));
|
||||||
|
if (Pluf::factory('IDF_EmailAddress')->get_user_for_email_address($this->cleaned_data['secondary_mail']) != null) {
|
||||||
|
throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used.'), $this->cleaned_data['secondary_mail']));
|
||||||
|
}
|
||||||
|
return $this->cleaned_data['secondary_mail'];
|
||||||
|
}
|
||||||
|
|
||||||
function clean_public_key()
|
function clean_public_key()
|
||||||
{
|
{
|
||||||
$this->cleaned_data['public_key'] =
|
$this->cleaned_data['public_key'] =
|
||||||
|
@ -53,7 +53,7 @@ class IDF_Form_UserChangeEmail extends Pluf_Form
|
|||||||
* Throw a Pluf_Form_Invalid exception if the key is not valid.
|
* Throw a Pluf_Form_Invalid exception if the key is not valid.
|
||||||
*
|
*
|
||||||
* @param string Key
|
* @param string Key
|
||||||
* @return array array($new_email, $user_id, time())
|
* @return array array($new_email, $user_id, time(), [primary|secondary])
|
||||||
*/
|
*/
|
||||||
public static function validateKey($key)
|
public static function validateKey($key)
|
||||||
{
|
{
|
||||||
@ -63,7 +63,7 @@ class IDF_Form_UserChangeEmail extends Pluf_Form
|
|||||||
throw new Pluf_Form_Invalid(__('The validation key is not valid. Please copy/paste it from your confirmation email.'));
|
throw new Pluf_Form_Invalid(__('The validation key is not valid. Please copy/paste it from your confirmation email.'));
|
||||||
}
|
}
|
||||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||||
return explode(':', $cr->decrypt($encrypted), 3);
|
return explode(':', $cr->decrypt($encrypted), 4);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ class IDF_Middleware
|
|||||||
'markdown' => 'IDF_Template_Markdown',
|
'markdown' => 'IDF_Template_Markdown',
|
||||||
'showuser' => 'IDF_Template_ShowUser',
|
'showuser' => 'IDF_Template_ShowUser',
|
||||||
'ashowuser' => 'IDF_Template_AssignShowUser',
|
'ashowuser' => 'IDF_Template_AssignShowUser',
|
||||||
|
'appversion' => 'IDF_Template_AppVersion',
|
||||||
));
|
));
|
||||||
$params['modifiers'] = array_merge($params['modifiers'],
|
$params['modifiers'] = array_merge($params['modifiers'],
|
||||||
array(
|
array(
|
||||||
|
43
src/IDF/Migrations/16AddUserMail.php
Normal file
43
src/IDF/Migrations/16AddUserMail.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?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 new IDF_Gconf model.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function IDF_Migrations_16AddUserMail_up($params=null)
|
||||||
|
{
|
||||||
|
$db = Pluf::db();
|
||||||
|
$schema = new Pluf_DB_Schema($db);
|
||||||
|
$schema->model = new IDF_EmailAddress();
|
||||||
|
$schema->createTables();
|
||||||
|
}
|
||||||
|
|
||||||
|
function IDF_Migrations_16AddUserMail_down($params=null)
|
||||||
|
{
|
||||||
|
$db = Pluf::db();
|
||||||
|
$schema = new Pluf_DB_Schema($db);
|
||||||
|
$schema->model = new IDF_EmailAddress();
|
||||||
|
$schema->dropTables();
|
||||||
|
}
|
@ -53,6 +53,7 @@ function IDF_Migrations_Backup_run($folder, $name=null)
|
|||||||
'IDF_Scm_Cache_Git',
|
'IDF_Scm_Cache_Git',
|
||||||
'IDF_Queue',
|
'IDF_Queue',
|
||||||
'IDF_Gconf',
|
'IDF_Gconf',
|
||||||
|
'IDF_EmailAddress',
|
||||||
);
|
);
|
||||||
$db = Pluf::db();
|
$db = Pluf::db();
|
||||||
// Now, for each table, we dump the content in json, this is a
|
// Now, for each table, we dump the content in json, this is a
|
||||||
@ -98,6 +99,7 @@ function IDF_Migrations_Backup_restore($folder, $name)
|
|||||||
'IDF_Scm_Cache_Git',
|
'IDF_Scm_Cache_Git',
|
||||||
'IDF_Queue',
|
'IDF_Queue',
|
||||||
'IDF_Gconf',
|
'IDF_Gconf',
|
||||||
|
'IDF_EmailAddress',
|
||||||
);
|
);
|
||||||
$db = Pluf::db();
|
$db = Pluf::db();
|
||||||
$schema = new Pluf_DB_Schema($db);
|
$schema = new Pluf_DB_Schema($db);
|
||||||
|
@ -50,6 +50,7 @@ function IDF_Migrations_Install_setup($params=null)
|
|||||||
'IDF_Scm_Cache_Git',
|
'IDF_Scm_Cache_Git',
|
||||||
'IDF_Queue',
|
'IDF_Queue',
|
||||||
'IDF_Gconf',
|
'IDF_Gconf',
|
||||||
|
'IDF_EmailAddress',
|
||||||
);
|
);
|
||||||
$db = Pluf::db();
|
$db = Pluf::db();
|
||||||
$schema = new Pluf_DB_Schema($db);
|
$schema = new Pluf_DB_Schema($db);
|
||||||
@ -107,6 +108,7 @@ function IDF_Migrations_Install_teardown($params=null)
|
|||||||
'IDF_Tag',
|
'IDF_Tag',
|
||||||
'IDF_Commit',
|
'IDF_Commit',
|
||||||
'IDF_Project',
|
'IDF_Project',
|
||||||
|
'IDF_EmailAddress',
|
||||||
);
|
);
|
||||||
$db = Pluf::db();
|
$db = Pluf::db();
|
||||||
$schema = new Pluf_DB_Schema($db);
|
$schema = new Pluf_DB_Schema($db);
|
||||||
|
@ -190,7 +190,12 @@ class IDF_Precondition
|
|||||||
return true; // Again need authentication error
|
return true; // Again need authentication error
|
||||||
}
|
}
|
||||||
$request->user = $users[0];
|
$request->user = $users[0];
|
||||||
IDF_Middleware::setRights($request);
|
|
||||||
|
// Don't try to load projects rights access if we are not in one
|
||||||
|
if ($request->query !== "/api/") {
|
||||||
|
IDF_Middleware::setRights($request);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,5 +473,14 @@ class IDF_Scm
|
|||||||
{
|
{
|
||||||
return str_replace('%2F', '/', rawurlencode($path));
|
return str_replace('%2F', '/', rawurlencode($path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of slashes and preceeding path components
|
||||||
|
* that should be stripped from paths in the SCM's diff output
|
||||||
|
*/
|
||||||
|
public function getDiffPathStripLevel()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,60 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
$this->project = $project;
|
$this->project = $project;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see IDF_Scm::getChanges()
|
||||||
|
*
|
||||||
|
* Git command output is like :
|
||||||
|
* M doc/Guide utilisateur/Manuel_distrib.tex
|
||||||
|
* M doc/Guide utilisateur/Manuel_intro.tex
|
||||||
|
* M doc/Guide utilisateur/Manuel_libpegase_exemples.tex
|
||||||
|
* M doc/Guide utilisateur/Manuel_page1_version.tex
|
||||||
|
* A doc/Guide utilisateur/images/ftp-nautilus.png
|
||||||
|
* M doc/Guide utilisateur/textes/log_boot_PEGASE.txt
|
||||||
|
*
|
||||||
|
* Status letters mean : Added (A), Deleted (D), Modified (M), Renamed (R)
|
||||||
|
*/
|
||||||
|
public function getChanges($commit)
|
||||||
|
{
|
||||||
|
$cmd = sprintf('GIT_DIR=%s '.Pluf::f('git_path', 'git').' show %s --name-status --pretty="format:" --diff-filter="[A|D|M|R]" -M',
|
||||||
|
escapeshellarg($this->repo),
|
||||||
|
escapeshellarg($commit));
|
||||||
|
$out = array();
|
||||||
|
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||||
|
self::exec('IDF_Scm_Git::getChanges', $cmd, $out);
|
||||||
|
|
||||||
|
$return = (object) array(
|
||||||
|
'additions' => array(),
|
||||||
|
'deletions' => array(),
|
||||||
|
'renames' => array(),
|
||||||
|
'patches' => array(),
|
||||||
|
'properties' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($out as $line) {
|
||||||
|
$line = trim($line);
|
||||||
|
if ($line != '') {
|
||||||
|
$action = $line[0];
|
||||||
|
|
||||||
|
if ($action == 'A') {
|
||||||
|
$filename = trim(substr($line, 1));
|
||||||
|
$return->additions[] = $filename;
|
||||||
|
} else if ($action == 'D') {
|
||||||
|
$filename = trim(substr($line, 1));
|
||||||
|
$return->deletions[] = $filename;
|
||||||
|
} else if ($action == 'M') {
|
||||||
|
$filename = trim(substr($line, 1));
|
||||||
|
$return->patches[] = $filename;
|
||||||
|
} else if ($action == 'R') {
|
||||||
|
$matches = split ("\t", $line);
|
||||||
|
$return->renames[$matches[1]] = $matches[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
public function getRepositorySize()
|
public function getRepositorySize()
|
||||||
{
|
{
|
||||||
if (!file_exists($this->repo)) {
|
if (!file_exists($this->repo)) {
|
||||||
@ -113,7 +167,29 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
*/
|
*/
|
||||||
public function inBranches($commit, $path)
|
public function inBranches($commit, $path)
|
||||||
{
|
{
|
||||||
return $this->_inObject($commit, 'branch');
|
if (isset($this->cache['inBranches'][$commit])) {
|
||||||
|
return $this->cache['inBranches'][$commit];
|
||||||
|
}
|
||||||
|
|
||||||
|
$cmd = Pluf::f('idf_exec_cmd_prefix', '')
|
||||||
|
.sprintf('GIT_DIR=%s %s branch --contains %s',
|
||||||
|
escapeshellarg($this->repo),
|
||||||
|
Pluf::f('git_path', 'git'),
|
||||||
|
escapeshellarg($commit));
|
||||||
|
self::exec('IDF_Scm_Git::inBranches', $cmd, $out, $return);
|
||||||
|
if (0 != $return) {
|
||||||
|
throw new IDF_Scm_Exception(sprintf($this->error_tpl,
|
||||||
|
$cmd, $return,
|
||||||
|
implode("\n", $out)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = array();
|
||||||
|
foreach ($out as $line) {
|
||||||
|
$res[] = substr($line, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cache['inBranches'][$commit] = $res;
|
||||||
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,35 +238,36 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
**/
|
**/
|
||||||
public function inTags($commit, $path)
|
public function inTags($commit, $path)
|
||||||
{
|
{
|
||||||
return $this->_inObject($commit, 'tag');
|
if (isset($this->cache['inTags'][$commit])) {
|
||||||
}
|
return $this->cache['inTags'][$commit];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
$cmd = Pluf::f('idf_exec_cmd_prefix', '')
|
||||||
* Returns in which branches or tags a commit is.
|
.sprintf('GIT_DIR=%s %s tag --contains %s',
|
||||||
*
|
escapeshellarg($this->repo),
|
||||||
* @param string Commit
|
Pluf::f('git_path', 'git'),
|
||||||
* @param string Object's type: 'branch' or 'tag'.
|
escapeshellarg($commit));
|
||||||
* @return array
|
self::exec('IDF_Scm_Git::inTags', $cmd, $out, $return);
|
||||||
*/
|
// `git tag` gained the `--contains` option in 1.6.2, earlier
|
||||||
private function _inObject($commit, $object)
|
// versions report a bad usage error (129) which we ignore here
|
||||||
{
|
if (129 == $return) {
|
||||||
$object = strtolower($object);
|
$this->cache['inTags'][$commit] = array();
|
||||||
if ('branch' === $object) {
|
return array();
|
||||||
$objects = $this->getBranches();
|
|
||||||
} else if ('tag' === $object) {
|
|
||||||
$objects = $this->getTags();
|
|
||||||
} else {
|
|
||||||
throw new InvalidArgumentException(sprintf(__('Invalid value for the parameter %1$s: %2$s. Use %3$s.'),
|
|
||||||
'$object',
|
|
||||||
$object,
|
|
||||||
'\'branch\' or \'tag\''));
|
|
||||||
}
|
}
|
||||||
unset($object);
|
// any other error should of course get noted
|
||||||
$result = array();
|
if (0 != $return) {
|
||||||
if (array_key_exists($commit, $objects)) {
|
throw new IDF_Scm_Exception(sprintf($this->error_tpl,
|
||||||
$result[] = $commit;
|
$cmd, $return,
|
||||||
|
implode("\n", $out)));
|
||||||
}
|
}
|
||||||
return $result;
|
|
||||||
|
$res = array();
|
||||||
|
foreach ($out as $line) {
|
||||||
|
$res[] = $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cache['inTags'][$commit] = $res;
|
||||||
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -271,14 +348,12 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
if (!preg_match('/<(.*)>/', $author, $match)) {
|
if (!preg_match('/<(.*)>/', $author, $match)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
foreach (array('email', 'login') as $what) {
|
$sql = new Pluf_SQL('login=%s', array($match[1]));
|
||||||
$sql = new Pluf_SQL($what.'=%s', array($match[1]));
|
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
if ($users->count() > 0) {
|
||||||
if ($users->count() > 0) {
|
return $users[0];
|
||||||
return $users[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return Pluf::factory('IDF_EmailAddress')->get_user_for_email_address($match[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAnonymousAccessUrl($project, $commit=null)
|
public static function getAnonymousAccessUrl($project, $commit=null)
|
||||||
@ -453,7 +528,7 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
$out[0]->diff = '';
|
$out[0]->diff = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$out[0]->branch = implode(', ', $this->inBranches($commit, null));
|
$out[0]->branch = implode(', ', $this->inBranches($out[0]->commit, null));
|
||||||
return $out[0];
|
return $out[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,6 +656,14 @@ class IDF_Scm_Git extends IDF_Scm
|
|||||||
return new Pluf_HTTP_Response_CommandPassThru($cmd, 'application/x-zip');
|
return new Pluf_HTTP_Response_CommandPassThru($cmd, 'application/x-zip');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see IDF_Scm::getDiffPathStripLevel()
|
||||||
|
*/
|
||||||
|
public function getDiffPathStripLevel()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* =====================================================
|
* =====================================================
|
||||||
* Specific Git Commands
|
* Specific Git Commands
|
||||||
|
@ -27,10 +27,13 @@
|
|||||||
*/
|
*/
|
||||||
class IDF_Scm_Mercurial extends IDF_Scm
|
class IDF_Scm_Mercurial extends IDF_Scm
|
||||||
{
|
{
|
||||||
|
protected $hg_log_template;
|
||||||
|
|
||||||
public function __construct($repo, $project=null)
|
public function __construct($repo, $project=null)
|
||||||
{
|
{
|
||||||
$this->repo = $repo;
|
$this->repo = $repo;
|
||||||
$this->project = $project;
|
$this->project = $project;
|
||||||
|
$this->hg_log_template = "'".'changeset: {rev}:{node|short}\nauthor: {author}\ndate: {date|isodate}\nfiles: {files}\n{desc}\n'."'";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRepositorySize()
|
public function getRepositorySize()
|
||||||
@ -67,9 +70,7 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
if (!preg_match('/<(.*)>/', $author, $match)) {
|
if (!preg_match('/<(.*)>/', $author, $match)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$sql = new Pluf_SQL('email=%s', array($match[1]));
|
return Pluf::factory('IDF_EmailAddress')->get_user_for_email_address($match[1]);
|
||||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
|
||||||
return ($users->count() > 0) ? $users[0] : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMainBranch()
|
public function getMainBranch()
|
||||||
@ -338,10 +339,14 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
if (!$this->isValidRevision($commit)) {
|
if (!$this->isValidRevision($commit)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$tmpl = ($getdiff) ?
|
$tmpl = ($getdiff)
|
||||||
Pluf::f('hg_path', 'hg').' log -p -r %s -R %s' : Pluf::f('hg_path', 'hg').' log -r %s -R %s';
|
? Pluf::f('hg_path', 'hg').' log -p -r %s -R %s --template %s'
|
||||||
|
: Pluf::f('hg_path', 'hg').' log -r %s -R %s --template %s';
|
||||||
$cmd = sprintf($tmpl,
|
$cmd = sprintf($tmpl,
|
||||||
escapeshellarg($commit), escapeshellarg($this->repo));
|
escapeshellarg($commit),
|
||||||
|
escapeshellarg($this->repo),
|
||||||
|
$this->hg_log_template);
|
||||||
|
|
||||||
$out = array();
|
$out = array();
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||||
self::exec('IDF_Scm_Mercurial::getCommit', $cmd, $out);
|
self::exec('IDF_Scm_Mercurial::getCommit', $cmd, $out);
|
||||||
@ -358,7 +363,7 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
$log[] = $line;
|
$log[] = $line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$out = self::parseLog($log, 6);
|
$out = self::parseLog($log, 4);
|
||||||
$out[0]->diff = implode("\n", $change);
|
$out[0]->diff = implode("\n", $change);
|
||||||
return $out[0];
|
return $out[0];
|
||||||
}
|
}
|
||||||
@ -383,11 +388,11 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
*/
|
*/
|
||||||
public function getChangeLog($commit='tip', $n=10)
|
public function getChangeLog($commit='tip', $n=10)
|
||||||
{
|
{
|
||||||
$cmd = sprintf(Pluf::f('hg_path', 'hg').' log -R %s -l%s ', escapeshellarg($this->repo), $n, $commit);
|
$cmd = sprintf(Pluf::f('hg_path', 'hg').' log -R %s -l%s --template %s', escapeshellarg($this->repo), $n, $this->hg_log_template, $commit);
|
||||||
$out = array();
|
$out = array();
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||||
self::exec('IDF_Scm_Mercurial::getChangeLog', $cmd, $out);
|
self::exec('IDF_Scm_Mercurial::getChangeLog', $cmd, $out);
|
||||||
return self::parseLog($out, 6);
|
return self::parseLog($out, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -423,7 +428,7 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$match = array();
|
$match = array();
|
||||||
if (preg_match('/(\S+)\s*:\s*(.*)/', $line, $match)) {
|
if (preg_match('/^(\S+):\s*(.*)/', $line, $match)) {
|
||||||
$match[1] = strtolower($match[1]);
|
$match[1] = strtolower($match[1]);
|
||||||
if ($match[1] == 'user') {
|
if ($match[1] == 'user') {
|
||||||
$c['author'] = $match[2];
|
$c['author'] = $match[2];
|
||||||
@ -458,7 +463,7 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
* @param string Prefix ('git-repo-dump')
|
* @param string Prefix ('git-repo-dump')
|
||||||
* @return Pluf_HTTP_Response The HTTP response containing the zip archive
|
* @return Pluf_HTTP_Response The HTTP response containing the zip archive
|
||||||
*/
|
*/
|
||||||
protected function getArchiveStream($commit, $prefix='')
|
public function getArchiveStream($commit, $prefix='')
|
||||||
{
|
{
|
||||||
$cmd = sprintf(Pluf::f('idf_exec_cmd_prefix', '').
|
$cmd = sprintf(Pluf::f('idf_exec_cmd_prefix', '').
|
||||||
Pluf::f('hg_path', 'hg').' archive --type=zip -R %s -r %s -',
|
Pluf::f('hg_path', 'hg').' archive --type=zip -R %s -r %s -',
|
||||||
@ -466,4 +471,12 @@ class IDF_Scm_Mercurial extends IDF_Scm
|
|||||||
escapeshellarg($commit));
|
escapeshellarg($commit));
|
||||||
return new Pluf_HTTP_Response_CommandPassThru($cmd, 'application/x-zip');
|
return new Pluf_HTTP_Response_CommandPassThru($cmd, 'application/x-zip');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see IDF_Scm::getDiffPathStripLevel()
|
||||||
|
*/
|
||||||
|
public function getDiffPathStripLevel()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,12 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
private static $instances = array();
|
private static $instances = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see IDF_Scm::__construct()
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public function __construct($project)
|
public function __construct(IDF_Project $project, IDF_Scm_Monotone_IStdio $stdio)
|
||||||
{
|
{
|
||||||
$this->project = $project;
|
$this->project = $project;
|
||||||
$this->stdio = new IDF_Scm_Monotone_Stdio($project);
|
$this->stdio = $stdio;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -400,14 +400,12 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
if (!preg_match('/([^ ]+@[^ ]+)/', $author, $match)) {
|
if (!preg_match('/([^ ]+@[^ ]+)/', $author, $match)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
foreach (array('email', 'login') as $what) {
|
$sql = new Pluf_SQL('login=%s', array($match[1]));
|
||||||
$sql = new Pluf_SQL($what.'=%s', array($match[1]));
|
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
if ($users->count() > 0) {
|
||||||
if ($users->count() > 0) {
|
return $users[0];
|
||||||
return $users[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return Pluf::factory('IDF_EmailAddress')->get_user_for_email_address($match[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -460,8 +458,9 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
public static function factory($project)
|
public static function factory($project)
|
||||||
{
|
{
|
||||||
if (!array_key_exists($project->shortname, self::$instances)) {
|
if (!array_key_exists($project->shortname, self::$instances)) {
|
||||||
|
$stdio = new IDF_Scm_Monotone_Stdio($project);
|
||||||
self::$instances[$project->shortname] =
|
self::$instances[$project->shortname] =
|
||||||
new IDF_Scm_Monotone($project);
|
new IDF_Scm_Monotone($project, $stdio);
|
||||||
}
|
}
|
||||||
return self::$instances[$project->shortname];
|
return self::$instances[$project->shortname];
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#
|
#
|
||||||
# ***** END LICENSE BLOCK ***** */
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
require_once 'IDF/Scm/Exception.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to parse and compile basic_io stanzas
|
* Utility class to parse and compile basic_io stanzas
|
||||||
*
|
*
|
||||||
@ -31,6 +33,11 @@ class IDF_Scm_Monotone_BasicIO
|
|||||||
/**
|
/**
|
||||||
* Parses monotone's basic_io format
|
* Parses monotone's basic_io format
|
||||||
*
|
*
|
||||||
|
* Known quirks:
|
||||||
|
* - does not handle multi-values starting with a hash '[]' (no known output)
|
||||||
|
* - does not validate hashes (should be /[0-9a-f]{40}/i)
|
||||||
|
* - does not handle forbidden \0
|
||||||
|
*
|
||||||
* @param string $in
|
* @param string $in
|
||||||
* @return array of arrays
|
* @return array of arrays
|
||||||
*/
|
*/
|
||||||
@ -54,50 +61,56 @@ class IDF_Scm_Monotone_BasicIO
|
|||||||
$stanzaLine['key'] .= $ch;
|
$stanzaLine['key'] .= $ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// symbol w/o a value list
|
// ensure we don't look at a symbol w/o a value list
|
||||||
if ($pos >= $length || $in[$pos] == "\n") break;
|
if ($pos >= $length || $in[$pos] == "\n") {
|
||||||
|
|
||||||
if ($in[$pos] == '[') {
|
|
||||||
unset($stanzaLine['values']);
|
unset($stanzaLine['values']);
|
||||||
++$pos; // opening square bracket
|
|
||||||
$stanzaLine['hash'] = substr($in, $pos, 40);
|
|
||||||
$pos += 40;
|
|
||||||
++$pos; // closing square bracket
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unset($stanzaLine['hash']);
|
unset($stanzaLine['hash']);
|
||||||
$valCount = 0;
|
}
|
||||||
// if hashs and plain values are encountered in the same
|
else {
|
||||||
// value list, we add the hash values as simple values as well
|
if ($in[$pos] == '[') {
|
||||||
while ($in[$pos] == '"' || $in[$pos] == '[') {
|
unset($stanzaLine['values']);
|
||||||
$isHashValue = $in[$pos] == '[';
|
++$pos; // opening square bracket
|
||||||
++$pos; // opening quote / bracket
|
while ($pos < $length && $in[$pos] != ']') {
|
||||||
$stanzaLine['values'][$valCount] = '';
|
$stanzaLine['hash'] .= $in[$pos];
|
||||||
while ($pos < $length) {
|
|
||||||
$ch = $in[$pos]; $pr = $in[$pos-1];
|
|
||||||
if (($isHashValue && $ch == ']')
|
|
||||||
||(!$isHashValue && $ch == '"' && $pr != '\\'))
|
|
||||||
break;
|
|
||||||
++$pos;
|
++$pos;
|
||||||
$stanzaLine['values'][$valCount] .= $ch;
|
|
||||||
}
|
}
|
||||||
++$pos; // closing quote
|
++$pos; // closing square bracket
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unset($stanzaLine['hash']);
|
||||||
|
$valCount = 0;
|
||||||
|
// if hashs and plain values are encountered in the same
|
||||||
|
// value list, we add the hash values as simple values as well
|
||||||
|
while ($in[$pos] == '"' || $in[$pos] == '[') {
|
||||||
|
$isHashValue = $in[$pos] == '[';
|
||||||
|
++$pos; // opening quote / bracket
|
||||||
|
$stanzaLine['values'][$valCount] = '';
|
||||||
|
while ($pos < $length) {
|
||||||
|
$ch = $in[$pos]; $pr = $in[$pos-1];
|
||||||
|
if (($isHashValue && $ch == ']')
|
||||||
|
||(!$isHashValue && $ch == '"' && $pr != '\\'))
|
||||||
|
break;
|
||||||
|
++$pos;
|
||||||
|
$stanzaLine['values'][$valCount] .= $ch;
|
||||||
|
}
|
||||||
|
++$pos; // closing quote
|
||||||
|
|
||||||
if (!$isHashValue) {
|
if (!$isHashValue) {
|
||||||
$stanzaLine['values'][$valCount] = str_replace(
|
$stanzaLine['values'][$valCount] = str_replace(
|
||||||
array("\\\\", "\\\""),
|
array("\\\\", "\\\""),
|
||||||
array("\\", "\""),
|
array("\\", "\""),
|
||||||
$stanzaLine['values'][$valCount]
|
$stanzaLine['values'][$valCount]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($pos >= $length)
|
if ($pos >= $length)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ($in[$pos] == ' ') {
|
if ($in[$pos] == ' ') {
|
||||||
++$pos; // space
|
++$pos; // space
|
||||||
++$valCount;
|
++$valCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,6 +127,12 @@ class IDF_Scm_Monotone_BasicIO
|
|||||||
/**
|
/**
|
||||||
* Compiles monotone's basicio format
|
* Compiles monotone's basicio format
|
||||||
*
|
*
|
||||||
|
* Known quirks:
|
||||||
|
* - does not validate keys for /[a-z_]+/
|
||||||
|
* - does not validate hashes (should be /[0-9a-f]{40}/i)
|
||||||
|
* - does not support intermixed value / hash formats
|
||||||
|
* - does not handle forbidden \0
|
||||||
|
*
|
||||||
* @param array $in Array of arrays
|
* @param array $in Array of arrays
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -129,7 +148,7 @@ class IDF_Scm_Monotone_BasicIO
|
|||||||
|
|
||||||
$maxkeylength = 0;
|
$maxkeylength = 0;
|
||||||
foreach ((array)$stanza as $lx => $line) {
|
foreach ((array)$stanza as $lx => $line) {
|
||||||
if (!array_key_exists('key', $line)) {
|
if (!array_key_exists('key', $line) || empty($line['key'])) {
|
||||||
throw new IDF_Scm_Exception(
|
throw new IDF_Scm_Exception(
|
||||||
'"key" not found in basicio stanza '.$sx.', line '.$lx
|
'"key" not found in basicio stanza '.$sx.', line '.$lx
|
||||||
);
|
);
|
||||||
@ -157,13 +176,6 @@ class IDF_Scm_Monotone_BasicIO
|
|||||||
$value).'"';
|
$value).'"';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IDF_Scm_Exception(
|
|
||||||
'neither "hash" nor "values" found in basicio '.
|
|
||||||
'stanza '.$sx.', line '.$lx
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$out .= "\n";
|
$out .= "\n";
|
||||||
}
|
}
|
||||||
|
66
src/IDF/Scm/Monotone/IStdio.php
Normal file
66
src/IDF/Scm/Monotone/IStdio.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?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) 2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monotone stdio interface
|
||||||
|
*
|
||||||
|
* @author Thomas Keller <me@thomaskeller.biz>
|
||||||
|
*/
|
||||||
|
interface IDF_Scm_Monotone_IStdio
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public function __construct(IDF_Project $project);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the stdio process and resets the command counter
|
||||||
|
*/
|
||||||
|
public function start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the stdio process and closes all pipes
|
||||||
|
*/
|
||||||
|
public function stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a command over stdio and returns its result
|
||||||
|
*
|
||||||
|
* @param array Array of arguments
|
||||||
|
* @param array Array of options as key-value pairs. Multiple options
|
||||||
|
* can be defined in sub-arrays, like
|
||||||
|
* "r" => array("123...", "456...")
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function exec(array $args, array $options = array());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last out-of-band output for a previously executed
|
||||||
|
* command as associative array with 'e' (error), 'w' (warning),
|
||||||
|
* 'p' (progress) and 't' (ticker, unparsed) as keys
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getLastOutOfBandOutput();
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,8 @@
|
|||||||
#
|
#
|
||||||
# ***** END LICENSE BLOCK ***** */
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
require_once 'IDF/Scm/Monotone/IStdio.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Monotone stdio class
|
* Monotone stdio class
|
||||||
*
|
*
|
||||||
@ -29,7 +31,7 @@
|
|||||||
*
|
*
|
||||||
* @author Thomas Keller <me@thomaskeller.biz>
|
* @author Thomas Keller <me@thomaskeller.biz>
|
||||||
*/
|
*/
|
||||||
class IDF_Scm_Monotone_Stdio
|
class IDF_Scm_Monotone_Stdio implements IDF_Scm_Monotone_IStdio
|
||||||
{
|
{
|
||||||
/** this is the most recent STDIO version. The number is output
|
/** this is the most recent STDIO version. The number is output
|
||||||
at the protocol start. Older versions of monotone (prior 0.47)
|
at the protocol start. Older versions of monotone (prior 0.47)
|
||||||
@ -68,7 +70,7 @@ class IDF_Scm_Monotone_Stdio
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function _getAuthOptions()
|
private function _getAuthOptions()
|
||||||
{
|
{
|
||||||
$prjconf = $this->project->getConf();
|
$prjconf = $this->project->getConf();
|
||||||
$name = $prjconf->getVal('mtn_client_key_name', false);
|
$name = $prjconf->getVal('mtn_client_key_name', false);
|
||||||
|
@ -45,7 +45,7 @@ class IDF_Scm_Monotone_ZipRender extends Pluf_HTTP_Response
|
|||||||
private $stdio = null;
|
private $stdio = null;
|
||||||
private $revision = null;
|
private $revision = null;
|
||||||
|
|
||||||
function __construct($stdio, $revision)
|
function __construct(IDF_Scm_Monotone_IStdio $stdio, $revision)
|
||||||
{
|
{
|
||||||
parent::__construct($revision, 'application/x-zip');
|
parent::__construct($revision, 'application/x-zip');
|
||||||
$this->stdio = $stdio;
|
$this->stdio = $stdio;
|
||||||
@ -60,6 +60,26 @@ class IDF_Scm_Monotone_ZipRender extends Pluf_HTTP_Response
|
|||||||
$this->outputHeaders();
|
$this->outputHeaders();
|
||||||
|
|
||||||
if ($output_body) {
|
if ($output_body) {
|
||||||
|
$certs = $this->stdio->exec(array('certs', $this->revision));
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse($certs);
|
||||||
|
|
||||||
|
// use the revision's date (if there is one) as timestamp
|
||||||
|
// for all file entries
|
||||||
|
$timestamp = time();
|
||||||
|
foreach ($stanzas as $stanza) {
|
||||||
|
$next_is_date = false;
|
||||||
|
foreach ($stanza as $line) {
|
||||||
|
if ($line['key'] == 'name' && $line['values'][0] == 'date') {
|
||||||
|
$next_is_date = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($next_is_date && $line['key'] == 'value') {
|
||||||
|
$timestamp = strtotime($line['values'][0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$manifest = $this->stdio->exec(array('get_manifest_of', $this->revision));
|
$manifest = $this->stdio->exec(array('get_manifest_of', $this->revision));
|
||||||
$stanzas = IDF_Scm_Monotone_BasicIO::parse($manifest);
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse($manifest);
|
||||||
|
|
||||||
@ -69,7 +89,11 @@ class IDF_Scm_Monotone_ZipRender extends Pluf_HTTP_Response
|
|||||||
if ($stanza[0]['key'] != 'file')
|
if ($stanza[0]['key'] != 'file')
|
||||||
continue;
|
continue;
|
||||||
$content = $this->stdio->exec(array('get_file', $stanza[1]['hash']));
|
$content = $this->stdio->exec(array('get_file', $stanza[1]['hash']));
|
||||||
$zip->add_file($stanza[0]['values'][0], $content);
|
$zip->add_file(
|
||||||
|
$stanza[0]['values'][0],
|
||||||
|
$content,
|
||||||
|
array('time' => $timestamp)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$zip->finish();
|
$zip->finish();
|
||||||
|
@ -266,8 +266,13 @@ class IDF_Scm_Svn extends IDF_Scm
|
|||||||
escapeshellarg($this->repo),
|
escapeshellarg($this->repo),
|
||||||
escapeshellarg($rev));
|
escapeshellarg($rev));
|
||||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
$cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd;
|
||||||
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getCommitMessage', $cmd));
|
try {
|
||||||
$this->cache['commitmess'][$rev] = (string) $xml->logentry->msg;
|
$xml = simplexml_load_string(self::shell_exec('IDF_Scm_Svn::getCommitMessage', $cmd));
|
||||||
|
$this->cache['commitmess'][$rev] = (string) $xml->logentry->msg;
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
$this->cache['commitmess'][$rev] = '';
|
||||||
|
}
|
||||||
return $this->cache['commitmess'][$rev];
|
return $this->cache['commitmess'][$rev];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
src/IDF/Template.php
Normal file
51
src/IDF/Template.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?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) 2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHP sets the backtrack limit quite low, so some (harder to analyze) regexes may fail
|
||||||
|
* unexpectedly on large inputs or weird cornercases (see issue 618). Unfortunately this
|
||||||
|
* fix does not always work and the execution time gets bigger the bigger we set the limit,
|
||||||
|
* so in case PCRE fails to analyze the input string and preg_replace(_callback) returns NULL,
|
||||||
|
* we at least return the input string unaltered.
|
||||||
|
*
|
||||||
|
* @param $pattern The pattern
|
||||||
|
* @param $mixed Callback or replacement string
|
||||||
|
* @param $input The input
|
||||||
|
* @return The output
|
||||||
|
*/
|
||||||
|
function IDF_Template_safePregReplace($pattern, $mixed, $input)
|
||||||
|
{
|
||||||
|
$pcre_backtrack_limit = ini_get('pcre.backtrack_limit');
|
||||||
|
ini_set('pcre.backtrack_limit', 10000000);
|
||||||
|
|
||||||
|
if (is_string($mixed) && !function_exists($mixed))
|
||||||
|
$output = preg_replace($pattern, $mixed, $input);
|
||||||
|
else
|
||||||
|
$output = preg_replace_callback($pattern, $mixed, $input);
|
||||||
|
|
||||||
|
if ($output === null)
|
||||||
|
$output = $input;
|
||||||
|
|
||||||
|
ini_set('pcre.backtrack_limit', $pcre_backtrack_limit);
|
||||||
|
return $output;
|
||||||
|
}
|
61
src/IDF/Template/AppVersion.php
Normal file
61
src/IDF/Template/AppVersion.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# This file is part of InDefero, an open source project management application.
|
||||||
|
# Copyright (C) 2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AppVersion tag.
|
||||||
|
*
|
||||||
|
* Renders two meta tags that include the application's version and revision
|
||||||
|
*/
|
||||||
|
class IDF_Template_AppVersion extends Pluf_Template_Tag
|
||||||
|
{
|
||||||
|
function start($file = 'IDF/version.php')
|
||||||
|
{
|
||||||
|
if (!Pluf::fileExists($file)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = include_once($file);
|
||||||
|
if (!is_array($info)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('version', $info)) {
|
||||||
|
echo '<meta name="indefero-version" content="'.$info['version'].'" />'."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('revision', $info)) {
|
||||||
|
if (strpos($info['revision'], '$') !== false) {
|
||||||
|
$info['revision'] = 'unknown';
|
||||||
|
$cmd = Pluf::f('idf_exec_cmd_prefix', '').
|
||||||
|
Pluf::f('git_path', 'git').
|
||||||
|
' log -1 --format=%H';
|
||||||
|
|
||||||
|
if (IDF_Scm::exec('IDF_Template_AppVersion::start', $cmd, $output)) {
|
||||||
|
$info['revision'] = trim(@$output[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo '<meta name="indefero-revision" content="'.$info['revision'].'" />'."\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,7 @@
|
|||||||
# ***** END LICENSE BLOCK ***** */
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||||
|
Pluf::loadFunction('IDF_Template_safePregReplace');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the links to issues and commits.
|
* Make the links to issues and commits.
|
||||||
@ -39,26 +40,26 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
|||||||
$this->scm = IDF_Scm::get($request->project);
|
$this->scm = IDF_Scm::get($request->project);
|
||||||
if ($esc) $text = Pluf_esc($text);
|
if ($esc) $text = Pluf_esc($text);
|
||||||
if ($autolink) {
|
if ($autolink) {
|
||||||
$text = preg_replace('#([a-z]+://[^\s\(\)]+)#i',
|
$text = IDF_Template_safePregReplace('#([a-z]+://[^\s\(\)]+)#i',
|
||||||
'<a href="\1">\1</a>', $text);
|
'<a href="\1">\1</a>', $text);
|
||||||
}
|
}
|
||||||
if ($request->rights['hasIssuesAccess']) {
|
if ($request->rights['hasIssuesAccess']) {
|
||||||
$text = preg_replace_callback('#((?:issue|bug|ticket)(s)?\s+|\s+\#)(\d+)(\#ic\d+)?(?(2)((?:[, \w]+(?:\s+\#)?)?\d+(?:\#ic\d+)?){0,})#im',
|
$text = IDF_Template_safePregReplace('#((?:issue|bug|ticket)(s)?\s+|\s+\#)(\d+)(\#ic\d+)?(?(2)((?:[, \w]+(?:\s+\#)?)?\d+(?:\#ic\d+)?){0,})#im',
|
||||||
array($this, 'callbackIssues'), $text);
|
array($this, 'callbackIssues'), $text);
|
||||||
}
|
}
|
||||||
if ($request->rights['hasReviewAccess']) {
|
if ($request->rights['hasReviewAccess']) {
|
||||||
$text = preg_replace_callback('#(reviews?\s+)(\d+(?:(?:\s+and|\s+or|,)\s+\d+)*)\b#i',
|
$text = IDF_Template_safePregReplace('#(reviews?\s+)(\d+(?:(?:\s+and|\s+or|,)\s+\d+)*)\b#i',
|
||||||
array($this, 'callbackReviews'), $text);
|
array($this, 'callbackReviews'), $text);
|
||||||
}
|
}
|
||||||
if ($request->rights['hasSourceAccess']) {
|
if ($request->rights['hasSourceAccess']) {
|
||||||
$verbs = array('added', 'fixed', 'reverted', 'changed', 'removed');
|
$verbs = array('added', 'fixed', 'reverted', 'changed', 'removed');
|
||||||
$nouns = array('commit', 'commits', 'revision', 'revisions', 'rev', 'revs');
|
$nouns = array('commit', 'commits', 'revision', 'revisions', 'rev', 'revs');
|
||||||
$prefix = implode(' in|', $verbs).' in' . '|'.
|
$prefix = implode(' in|', $verbs).' in' . '|'.
|
||||||
implode('|', $nouns);
|
implode('|', $nouns);
|
||||||
$text = preg_replace_callback('#((?:'.$prefix.')(?:\s+r?))([0-9a-f]{1,40}((?:\s+and|\s+or|,)\s+r?[0-9a-f]{1,40})*)\b#i',
|
$text = IDF_Template_safePregReplace('#((?:'.$prefix.')(?:\s+r?))([0-9a-f]{1,40}((?:\s+and|\s+or|,)\s+r?[0-9a-f]{1,40})*)\b#i',
|
||||||
array($this, 'callbackCommits'), $text);
|
array($this, 'callbackCommits'), $text);
|
||||||
$text = preg_replace_callback('=(src:)([^\s@#,\(\)\\\\]+(?:(\\\\)[\s@#][^\s@#,\(\)\\\\]+){0,})+(?:\@([^\s#,]+))(?:#(\d+))?=im',
|
$text = IDF_Template_safePregReplace('=(src:)([^\s@#,\(\)\\\\]+(?:(\\\\)[\s@#][^\s@#,\(\)\\\\]+){0,})+(?:\@([^\s#,]+))(?:#(\d+))?=im',
|
||||||
array($this, 'callbackSource'), $text);
|
array($this, 'callbackSource'), $text);
|
||||||
}
|
}
|
||||||
if ($wordwrap) $text = Pluf_Text::wrapHtml($text, 69, "\n");
|
if ($wordwrap) $text = Pluf_Text::wrapHtml($text, 69, "\n");
|
||||||
if ($nl2br) $text = nl2br($text);
|
if ($nl2br) $text = nl2br($text);
|
||||||
@ -94,9 +95,9 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
|||||||
}
|
}
|
||||||
return $m[0]; // not existing issue.
|
return $m[0]; // not existing issue.
|
||||||
}
|
}
|
||||||
return preg_replace_callback('#(\#)?(\d+)(\#ic\d+)?#',
|
return IDF_Template_safePregReplace('#(\#)?(\d+)(\#ic\d+)?#',
|
||||||
array($this, 'callbackIssue'),
|
array($this, 'callbackIssue'),
|
||||||
$m[0]);
|
$m[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,7 +132,7 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
|||||||
return $m[1].call_user_func(array($this, 'callbackCommit'), array($m[2]));
|
return $m[1].call_user_func(array($this, 'callbackCommit'), array($m[2]));
|
||||||
}
|
}
|
||||||
// Multiple commits like 'commits 6e030e6, a25bfc1 and 3c094f8'.
|
// Multiple commits like 'commits 6e030e6, a25bfc1 and 3c094f8'.
|
||||||
return $m[1].preg_replace_callback('#\b[0-9a-f]{1,40}\b#i', array($this, 'callbackCommit'), $m[2]);
|
return $m[1].IDF_Template_safePregReplace('#\b[0-9a-f]{1,40}\b#i', array($this, 'callbackCommit'), $m[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,7 +164,7 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
|
|||||||
{
|
{
|
||||||
$keyword = rtrim($m[1]);
|
$keyword = rtrim($m[1]);
|
||||||
if ('reviews' === $keyword) {
|
if ('reviews' === $keyword) {
|
||||||
return $m[1].preg_replace_callback('#\b(\d+)\b#i', array($this, 'callbackReview'), $m[2]);
|
return $m[1].IDF_Template_safePregReplace('#\b(\d+)\b#i', array($this, 'callbackReview'), $m[2]);
|
||||||
} else if ('review' === $keyword) {
|
} else if ('review' === $keyword) {
|
||||||
return $m[1].call_user_func(array($this, 'callbackReview'), array('', $m[2]));
|
return $m[1].call_user_func(array($this, 'callbackReview'), array('', $m[2]));
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
# ***** END LICENSE BLOCK ***** */
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
Pluf::loadFunction('Pluf_Text_MarkDown_parse');
|
Pluf::loadFunction('Pluf_Text_MarkDown_parse');
|
||||||
|
Pluf::loadFunction('IDF_Template_safePregReplace');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the links to issues and commits.
|
* Make the links to issues and commits.
|
||||||
@ -42,18 +43,18 @@ class IDF_Template_Markdown extends Pluf_Template_Tag
|
|||||||
// Replace [[[path/to/file.mdtext, commit]]] with embedding
|
// Replace [[[path/to/file.mdtext, commit]]] with embedding
|
||||||
// the content of the file into the wki page
|
// the content of the file into the wki page
|
||||||
if ($this->request->rights['hasSourceAccess']) {
|
if ($this->request->rights['hasSourceAccess']) {
|
||||||
$text = preg_replace_callback('#\[\[\[([^\,]+)(?:, ([^/]+))?\]\]\]#im',
|
$text = IDF_Template_safePregReplace('#\[\[\[([^\,]+)(?:, ([^/]+))?\]\]\]#im',
|
||||||
array($this, 'callbackEmbeddedDoc'),
|
array($this, 'callbackEmbeddedDoc'),
|
||||||
$text);
|
$text);
|
||||||
}
|
}
|
||||||
// Replace [Page]([[PageName]]) with corresponding link to the page, with link text being Page.
|
// Replace [Page]([[PageName]]) with corresponding link to the page, with link text being Page.
|
||||||
$text = preg_replace_callback('#\[([^\]]+)\]\(\[\[([A-Za-z0-9\-]+)\]\]\)#im',
|
$text = IDF_Template_safePregReplace('#\[([^\]]+)\]\(\[\[([A-Za-z0-9\-]+)\]\]\)#im',
|
||||||
array($this, 'callbackWikiPage'),
|
array($this, 'callbackWikiPage'),
|
||||||
$text);
|
$text);
|
||||||
// Replace [[PageName]] with corresponding link to the page.
|
// Replace [[PageName]] with corresponding link to the page.
|
||||||
$text = preg_replace_callback('#\[\[([A-Za-z0-9\-]+)\]\]#im',
|
$text = IDF_Template_safePregReplace('#\[\[([A-Za-z0-9\-]+)\]\]#im',
|
||||||
array($this, 'callbackWikiPageNoName'),
|
array($this, 'callbackWikiPageNoName'),
|
||||||
$text);
|
$text);
|
||||||
$filter = new IDF_Template_MarkdownPrefilter();
|
$filter = new IDF_Template_MarkdownPrefilter();
|
||||||
echo $filter->go(Pluf_Text_MarkDown_parse($text));
|
echo $filter->go(Pluf_Text_MarkDown_parse($text));
|
||||||
}
|
}
|
||||||
|
@ -32,29 +32,6 @@ class IDF_Tests_TestDiff extends UnitTestCase
|
|||||||
parent::__construct('Test the diff parser.');
|
parent::__construct('Test the diff parser.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetFile()
|
|
||||||
{
|
|
||||||
$lines = array(
|
|
||||||
'diff --git a/src/IDF/Form/Register.php b/src/IDF/Form/Register.php',
|
|
||||||
'diff --git a/src/IDF/Form/RegisterConfirmation.php b/src/IDF/Form/RegisterConfirmation.php',
|
|
||||||
'diff --git a/src/IDF/Form/RegisterInputKey.php b/src/IDF/Form/RegisterInputKey.php',
|
|
||||||
'diff --git a/src/IDF/Views.php b/src/IDF/Views.php',
|
|
||||||
'diff --git a/src/IDF/conf/views.php b/src/IDF/conf/views.php',
|
|
||||||
);
|
|
||||||
$files = array(
|
|
||||||
'src/IDF/Form/Register.php',
|
|
||||||
'src/IDF/Form/RegisterConfirmation.php',
|
|
||||||
'src/IDF/Form/RegisterInputKey.php',
|
|
||||||
'src/IDF/Views.php',
|
|
||||||
'src/IDF/conf/views.php',
|
|
||||||
);
|
|
||||||
$i = 0;
|
|
||||||
foreach ($lines as $line) {
|
|
||||||
$this->assertEqual($files[$i], IDF_Diff::getFile($line));
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testBinaryDiff()
|
public function testBinaryDiff()
|
||||||
{
|
{
|
||||||
$diff_content = file_get_contents(dirname(__FILE__).'/test-diff.diff');
|
$diff_content = file_get_contents(dirname(__FILE__).'/test-diff.diff');
|
||||||
|
@ -37,12 +37,16 @@ class IDF_Views
|
|||||||
* Only the public projects are listed or the private with correct
|
* Only the public projects are listed or the private with correct
|
||||||
* rights.
|
* rights.
|
||||||
*/
|
*/
|
||||||
public function index($request, $match)
|
public function index($request, $match, $api=false)
|
||||||
{
|
{
|
||||||
$projects = self::getProjects($request->user);
|
$projects = self::getProjects($request->user);
|
||||||
|
$stats = self::getProjectsStatistics ($projects);
|
||||||
|
|
||||||
|
if ($api == true) return $projects;
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/index.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/index.html',
|
||||||
array('page_title' => __('Projects'),
|
array('page_title' => __('Projects'),
|
||||||
'projects' => $projects),
|
'projects' => $projects,
|
||||||
|
'stats' => new Pluf_Template_ContextVars($stats)),
|
||||||
$request);
|
$request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,4 +347,40 @@ class IDF_Views
|
|||||||
return Pluf::factory('IDF_Project')->getList(array('filter' => $sql,
|
return Pluf::factory('IDF_Project')->getList(array('filter' => $sql,
|
||||||
'order' => 'name ASC'));
|
'order' => 'name ASC'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns statistics on a list of projects.
|
||||||
|
*
|
||||||
|
* @param ArrayObject IDF_Project
|
||||||
|
* @return Associative array of statistics
|
||||||
|
*/
|
||||||
|
public static function getProjectsStatistics($projects)
|
||||||
|
{
|
||||||
|
// Init the return var
|
||||||
|
$forgestats = array('downloads' => 0,
|
||||||
|
'reviews' => 0,
|
||||||
|
'issues' => 0,
|
||||||
|
'docpages' => 0,
|
||||||
|
'commits' => 0);
|
||||||
|
|
||||||
|
// Count for each projects
|
||||||
|
foreach ($projects as $p) {
|
||||||
|
$pstats = $p->getStats ();
|
||||||
|
$forgestats['downloads'] += $pstats['downloads'];
|
||||||
|
$forgestats['reviews'] += $pstats['reviews'];
|
||||||
|
$forgestats['issues'] += $pstats['issues'];
|
||||||
|
$forgestats['docpages'] += $pstats['docpages'];
|
||||||
|
$forgestats['commits'] += $pstats['commits'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count projects
|
||||||
|
$forgestats['projects'] = count($projects);
|
||||||
|
|
||||||
|
// Count members
|
||||||
|
$sql = new Pluf_SQL('first_name != %s', array('---'));
|
||||||
|
$forgestats['members'] = Pluf::factory('Pluf_User')
|
||||||
|
->getCount(array('filter' => $sql->gen()));
|
||||||
|
|
||||||
|
return $forgestats;
|
||||||
|
}
|
||||||
}
|
}
|
@ -55,6 +55,7 @@ class IDF_Views_Api
|
|||||||
* Create a new issue.
|
* Create a new issue.
|
||||||
*/
|
*/
|
||||||
public $issueCreate_precond = array('IDF_Precondition::apiSetUser',
|
public $issueCreate_precond = array('IDF_Precondition::apiSetUser',
|
||||||
|
'Pluf_Precondition::loginRequired',
|
||||||
'IDF_Precondition::accessIssues');
|
'IDF_Precondition::accessIssues');
|
||||||
public function issueCreate($request, $match)
|
public function issueCreate($request, $match)
|
||||||
{
|
{
|
||||||
@ -63,7 +64,7 @@ class IDF_Views_Api
|
|||||||
$out = array();
|
$out = array();
|
||||||
if ($request->method == 'GET') {
|
if ($request->method == 'GET') {
|
||||||
// We give the details of the form
|
// We give the details of the form
|
||||||
$out['doc'] = 'A POST request against this url will allow you to create a new issue.';
|
$out['help'] = 'A POST request against this url will allow you to create a new issue.';
|
||||||
if ($request->user->hasPerm('IDF.project-owner', $request->project)
|
if ($request->user->hasPerm('IDF.project-owner', $request->project)
|
||||||
or $request->user->hasPerm('IDF.project-member', $request->project)) {
|
or $request->user->hasPerm('IDF.project-member', $request->project)) {
|
||||||
$out['status'] = array();
|
$out['status'] = array();
|
||||||
@ -75,16 +76,37 @@ class IDF_Views_Api
|
|||||||
} else {
|
} else {
|
||||||
// We need to give back the results of the creation
|
// We need to give back the results of the creation
|
||||||
if (is_object($p) and 'IDF_Issue' == get_class($p)) {
|
if (is_object($p) and 'IDF_Issue' == get_class($p)) {
|
||||||
$out['mess'] = 'success';
|
$out['message'] = 'success';
|
||||||
$out['issue'] = $p->id;
|
$out['issue'] = $p->id;
|
||||||
} else {
|
} else {
|
||||||
$out['mess'] = 'error';
|
$out['message'] = 'error';
|
||||||
$out['errors'] = $p['form']->errors;
|
$out['errors'] = $p['form']->errors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Pluf_HTTP_Response_Json($out);
|
return new Pluf_HTTP_Response_Json($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all the projects
|
||||||
|
*/
|
||||||
|
public $projectIndex_precond = array('IDF_Precondition::apiSetUser');
|
||||||
|
|
||||||
|
public function projectIndex($request, $match)
|
||||||
|
{
|
||||||
|
$view = new IDF_Views();
|
||||||
|
$projects = $view->index($request, $match, true);
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
foreach ($projects as $p) {
|
||||||
|
$data[] = array("shortname" => $p->shortname, "name" => $p->name, "shortdesc" => $p->shortdesc, "private" => $p->private);
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = array();
|
||||||
|
$out['message'] = 'success';
|
||||||
|
$out['projects'] = $data;
|
||||||
|
return new Pluf_HTTP_Response_Json($out);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of tags to give them to the end users when doing a
|
* Get the list of tags to give them to the end users when doing a
|
||||||
* GET request against a form. That way it is possible for them to
|
* GET request against a form. That way it is possible for them to
|
||||||
|
@ -71,12 +71,10 @@ class IDF_Views_Download
|
|||||||
$pag->no_results_text = __('No downloads were found.');
|
$pag->no_results_text = __('No downloads were found.');
|
||||||
$pag->sort_order = array('creation_dtime', 'DESC');
|
$pag->sort_order = array('creation_dtime', 'DESC');
|
||||||
$pag->setFromRequest($request);
|
$pag->setFromRequest($request);
|
||||||
$tags = $prj->getTagCloud('downloads');
|
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/downloads/index.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/downloads/index.html',
|
||||||
array(
|
array(
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'downloads' => $pag,
|
'downloads' => $pag,
|
||||||
'tags' => $tags,
|
|
||||||
'deprecated' => count($ids),
|
'deprecated' => count($ids),
|
||||||
'dlabel' => $dtag,
|
'dlabel' => $dtag,
|
||||||
),
|
),
|
||||||
|
@ -71,8 +71,7 @@ class IDF_Views_Issue
|
|||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'open' => $open,
|
'open' => $open,
|
||||||
'closed' => $closed,
|
'closed' => $closed,
|
||||||
'issues' => $pag,
|
'issues' => $pag);
|
||||||
'cloud' => 'issues');
|
|
||||||
if ($api) return $params;
|
if ($api) return $params;
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/index.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/issues/index.html',
|
||||||
$params, $request);
|
$params, $request);
|
||||||
|
@ -31,6 +31,25 @@ Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
|
|||||||
*/
|
*/
|
||||||
class IDF_Views_Project
|
class IDF_Views_Project
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Home page of a project.
|
||||||
|
*/
|
||||||
|
public $logo_precond = array('IDF_Precondition::baseAccess');
|
||||||
|
public function logo($request, $match)
|
||||||
|
{
|
||||||
|
$prj = $request->project;
|
||||||
|
|
||||||
|
$logo = $prj->getConf()->getVal('logo');
|
||||||
|
if (empty($logo)) {
|
||||||
|
$url = Pluf::f('url_media') . '/idf/img/no_logo.png';
|
||||||
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = IDF_FileUtil::getMimeType($logo);
|
||||||
|
return new Pluf_HTTP_Response_File(Pluf::f('upload_path') . '/' . $prj->shortname . $logo,
|
||||||
|
$info[0]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Home page of a project.
|
* Home page of a project.
|
||||||
*/
|
*/
|
||||||
@ -62,20 +81,26 @@ class IDF_Views_Project
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an associative array with available model filters
|
* Returns an associative array with all accessible model filters
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private static function getAvailableModelFilters()
|
private static function getAccessibleModelFilters($request)
|
||||||
{
|
{
|
||||||
return array(
|
$filters = array('all' => __('All Updates'));
|
||||||
'all' => __('All Updates'),
|
|
||||||
'commits' => __('Commits'),
|
if (true === IDF_Precondition::accessSource($request))
|
||||||
'issues' => __('Issues and Comments'),
|
$filters['commits'] = __('Commits');
|
||||||
'downloads' => __('Downloads'),
|
if (true === IDF_Precondition::accessIssues($request))
|
||||||
'documents' => __('Documents'),
|
$filters['issues'] = __('Issues and Comments');
|
||||||
'reviews' => __('Reviews and Patches'),
|
if (true === IDF_Precondition::accessDownloads($request))
|
||||||
);
|
$filters['downloads'] = __('Downloads');
|
||||||
|
if (true === IDF_Precondition::accessWiki($request))
|
||||||
|
$filters['documents'] = __('Documents');
|
||||||
|
if (true === IDF_Precondition::accessReview($request))
|
||||||
|
$filters['reviews'] = __('Reviews and Patches');
|
||||||
|
|
||||||
|
return $filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,6 +146,17 @@ class IDF_Views_Project
|
|||||||
return $classes;
|
return $classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This action serves as URI compatibility layer for v1.0.
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
public function timelineCompat($request, $match)
|
||||||
|
{
|
||||||
|
$match[2] = 'all';
|
||||||
|
return $this->timeline($request, $match);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timeline of the project.
|
* Timeline of the project.
|
||||||
*/
|
*/
|
||||||
@ -130,11 +166,11 @@ class IDF_Views_Project
|
|||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
|
|
||||||
$model_filter = @$match[2];
|
$model_filter = @$match[2];
|
||||||
$all_model_filters = self::getAvailableModelFilters();
|
$accessible_model_filters = self::getAccessibleModelFilters($request);
|
||||||
if (!array_key_exists($model_filter, $all_model_filters)) {
|
if (!array_key_exists($model_filter, $accessible_model_filters)) {
|
||||||
$model_filter = 'all';
|
$model_filter = 'all';
|
||||||
}
|
}
|
||||||
$title = (string)$prj . ' ' . $all_model_filters[$model_filter];
|
$title = (string)$prj . ' ' . $accessible_model_filters[$model_filter];
|
||||||
|
|
||||||
$pag = new IDF_Timeline_Paginator(new IDF_Timeline());
|
$pag = new IDF_Timeline_Paginator(new IDF_Timeline());
|
||||||
$pag->class = 'recent-issues';
|
$pag->class = 'recent-issues';
|
||||||
@ -172,12 +208,23 @@ class IDF_Views_Project
|
|||||||
'feedurl' => $feedurl,
|
'feedurl' => $feedurl,
|
||||||
'timeline' => $pag,
|
'timeline' => $pag,
|
||||||
'model_filter' => $model_filter,
|
'model_filter' => $model_filter,
|
||||||
'all_model_filters' => $all_model_filters,
|
'accessible_model_filters' => $accessible_model_filters,
|
||||||
),
|
),
|
||||||
$request);
|
$request);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This action serves as URI compatibility layer for v1.0.
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
public function timelineFeedCompat($request, $match)
|
||||||
|
{
|
||||||
|
$match[2] = 'all';
|
||||||
|
return $this->timelineFeed($request, $match);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timeline feed.
|
* Timeline feed.
|
||||||
*
|
*
|
||||||
@ -192,12 +239,11 @@ class IDF_Views_Project
|
|||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
$model_filter = @$match[2];
|
$model_filter = @$match[2];
|
||||||
|
|
||||||
$model_filter = @$match[2];
|
$accessible_model_filters = self::getAccessibleModelFilters($request);
|
||||||
$all_model_filters = self::getAvailableModelFilters();
|
if (!array_key_exists($model_filter, $accessible_model_filters)) {
|
||||||
if (!array_key_exists($model_filter, $all_model_filters)) {
|
|
||||||
$model_filter = 'all';
|
$model_filter = 'all';
|
||||||
}
|
}
|
||||||
$title = $all_model_filters[$model_filter];
|
$title = $accessible_model_filters[$model_filter];
|
||||||
|
|
||||||
$classes = self::determineModelClasses($request, $model_filter);
|
$classes = self::determineModelClasses($request, $model_filter);
|
||||||
$sqls = sprintf('model_class IN (%s)', implode(', ', $classes));
|
$sqls = sprintf('model_class IN (%s)', implode(', ', $classes));
|
||||||
@ -246,29 +292,29 @@ class IDF_Views_Project
|
|||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
$title = sprintf(__('%s Project Summary'), (string) $prj);
|
$title = sprintf(__('%s Project Summary'), (string) $prj);
|
||||||
$form_fields = array('fields'=> array('name', 'shortdesc',
|
$extra = array('project' => $prj);
|
||||||
'description'));
|
|
||||||
if ($request->method == 'POST') {
|
if ($request->method == 'POST') {
|
||||||
$form = Pluf_Shortcuts_GetFormForModel($prj, $request->POST,
|
$form = new IDF_Form_ProjectConf(array_merge($request->POST,
|
||||||
$form_fields);
|
$request->FILES),
|
||||||
|
$extra);
|
||||||
if ($form->isValid()) {
|
if ($form->isValid()) {
|
||||||
$prj = $form->save();
|
$form->save();
|
||||||
$request->user->setMessage(__('The project has been updated.'));
|
$request->user->setMessage(__('The project has been updated.'));
|
||||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Project::admin',
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Project::admin',
|
||||||
array($prj->shortname));
|
array($prj->shortname));
|
||||||
return new Pluf_HTTP_Response_Redirect($url);
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$form = Pluf_Shortcuts_GetFormForModel($prj, $prj->getData(),
|
$form = new IDF_Form_ProjectConf($prj->getData(), $extra);
|
||||||
$form_fields);
|
|
||||||
}
|
}
|
||||||
$form->fields['description']->widget->attrs['cols'] = 68;
|
|
||||||
$form->fields['description']->widget->attrs['rows'] = 26;
|
$logo = $prj->getConf()->getVal('logo');
|
||||||
$form->fields['shortdesc']->widget->attrs['size'] = 67;
|
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/admin/summary.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/admin/summary.html',
|
||||||
array(
|
array(
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
|
'project' => $prj,
|
||||||
|
'logo' => $logo,
|
||||||
),
|
),
|
||||||
$request);
|
$request);
|
||||||
}
|
}
|
||||||
|
@ -56,11 +56,15 @@ class IDF_Views_Source
|
|||||||
public function invalidRevision($request, $match)
|
public function invalidRevision($request, $match)
|
||||||
{
|
{
|
||||||
$title = sprintf(__('%s Invalid Revision'), (string) $request->project);
|
$title = sprintf(__('%s Invalid Revision'), (string) $request->project);
|
||||||
|
$scm = IDF_Scm::get($request->project);
|
||||||
|
$branches = $scm->getBranches();
|
||||||
|
|
||||||
$commit = $match[2];
|
$commit = $match[2];
|
||||||
$params = array(
|
$params = array(
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'commit' => $commit,
|
'commit' => $commit,
|
||||||
|
'branches' => $branches,
|
||||||
);
|
);
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/source/invalid_revision.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/source/invalid_revision.html',
|
||||||
$params, $request);
|
$params, $request);
|
||||||
@ -299,7 +303,8 @@ class IDF_Views_Source
|
|||||||
$title = sprintf(__('%s Commit Details'), (string) $request->project);
|
$title = sprintf(__('%s Commit Details'), (string) $request->project);
|
||||||
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
|
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
|
||||||
$rcommit = IDF_Commit::getOrAdd($cobject, $request->project);
|
$rcommit = IDF_Commit::getOrAdd($cobject, $request->project);
|
||||||
$diff = new IDF_Diff($cobject->diff);
|
$diff = new IDF_Diff($cobject->diff, $scm->getDiffPathStripLevel());
|
||||||
|
$cobject->diff = null;
|
||||||
$diff->parse();
|
$diff->parse();
|
||||||
$scmConf = $request->conf->getVal('scm', 'git');
|
$scmConf = $request->conf->getVal('scm', 'git');
|
||||||
try {
|
try {
|
||||||
|
@ -127,12 +127,14 @@ class IDF_Views_User
|
|||||||
$form = new IDF_Form_UserAccount(null, $params);
|
$form = new IDF_Form_UserAccount(null, $params);
|
||||||
}
|
}
|
||||||
$keys = $request->user->get_idf_key_list();
|
$keys = $request->user->get_idf_key_list();
|
||||||
|
$mailaddrs = Pluf::factory('IDF_EmailAddress')->get_email_addresses_for_user($request->user);
|
||||||
|
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/user/myaccount.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/user/myaccount.html',
|
||||||
array('page_title' => __('Your Account'),
|
array('page_title' => __('Your Account'),
|
||||||
'api_key' => $api_key,
|
'api_key' => $api_key,
|
||||||
'ext_pass' => $ext_pass,
|
'ext_pass' => $ext_pass,
|
||||||
'keys' => $keys,
|
'keys' => $keys,
|
||||||
|
'mailaddrs' => $mailaddrs,
|
||||||
'form' => $form),
|
'form' => $form),
|
||||||
$request);
|
$request);
|
||||||
}
|
}
|
||||||
@ -157,6 +159,26 @@ class IDF_Views_User
|
|||||||
return new Pluf_HTTP_Response_Redirect($url);
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a mail address.
|
||||||
|
*
|
||||||
|
* This is redirecting to the preferences
|
||||||
|
*/
|
||||||
|
public $deleteMail_precond = array('Pluf_Precondition::loginRequired');
|
||||||
|
public function deleteMail($request, $match)
|
||||||
|
{
|
||||||
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_User::myAccount');
|
||||||
|
if ($request->method == 'POST') {
|
||||||
|
$address = Pluf_Shortcuts_GetObjectOr404('IDF_EmailAddress', $match[1]);
|
||||||
|
if ($address->user != $request->user->id) {
|
||||||
|
return new Pluf_HTTP_Response_Forbidden($request);
|
||||||
|
}
|
||||||
|
$address->delete();
|
||||||
|
$request->user->setMessage(__('The address has been deleted.'));
|
||||||
|
}
|
||||||
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter the key to change an email address.
|
* Enter the key to change an email address.
|
||||||
*
|
*
|
||||||
@ -190,7 +212,7 @@ class IDF_Views_User
|
|||||||
$key = $match[1];
|
$key = $match[1];
|
||||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailInputKey');
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailInputKey');
|
||||||
try {
|
try {
|
||||||
list($email, $id, $time) = IDF_Form_UserChangeEmail::validateKey($key);
|
list($email, $id, $time, $type) = IDF_Form_UserChangeEmail::validateKey($key);
|
||||||
} catch (Pluf_Form_Invalid $e) {
|
} catch (Pluf_Form_Invalid $e) {
|
||||||
return new Pluf_HTTP_Response_Redirect($url);
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
}
|
}
|
||||||
@ -198,8 +220,15 @@ class IDF_Views_User
|
|||||||
return new Pluf_HTTP_Response_Redirect($url);
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
}
|
}
|
||||||
// Now we have a change link coming from the right user.
|
// Now we have a change link coming from the right user.
|
||||||
$request->user->email = $email;
|
if ($type == "primary") {
|
||||||
$request->user->update();
|
$request->user->email = $email;
|
||||||
|
$request->user->update();
|
||||||
|
} else {
|
||||||
|
$mailaddress = new IDF_EmailAddress();
|
||||||
|
$mailaddress->user = $request->user;
|
||||||
|
$mailaddress->address = $email;
|
||||||
|
$mailaddress->create();
|
||||||
|
}
|
||||||
$request->user->setMessage(sprintf(__('Your new email address "%s" has been validated. Thank you!'), Pluf_esc($email)));
|
$request->user->setMessage(sprintf(__('Your new email address "%s" has been validated. Thank you!'), Pluf_esc($email)));
|
||||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_User::myAccount');
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_User::myAccount');
|
||||||
return new Pluf_HTTP_Response_Redirect($url);
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
|
@ -67,12 +67,10 @@ class IDF_Views_Wiki
|
|||||||
$pag->no_results_text = __('No documentation pages were found.');
|
$pag->no_results_text = __('No documentation pages were found.');
|
||||||
$pag->sort_order = array('title', 'ASC');
|
$pag->sort_order = array('title', 'ASC');
|
||||||
$pag->setFromRequest($request);
|
$pag->setFromRequest($request);
|
||||||
$tags = $prj->getTagCloud('wiki');
|
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
|
||||||
array(
|
array(
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'pages' => $pag,
|
'pages' => $pag,
|
||||||
'tags' => $tags,
|
|
||||||
'deprecated' => count($ids),
|
'deprecated' => count($ids),
|
||||||
'dlabel' => $dtag,
|
'dlabel' => $dtag,
|
||||||
),
|
),
|
||||||
|
@ -246,7 +246,7 @@ $cfg['template_context_processors'] = array('IDF_Middleware_ContextPreProcessor'
|
|||||||
$cfg['idf_views'] = dirname(__FILE__).'/urls.php';
|
$cfg['idf_views'] = dirname(__FILE__).'/urls.php';
|
||||||
|
|
||||||
# available languages
|
# available languages
|
||||||
$cfg['languages'] = array('en', 'fr');
|
$cfg['languages'] = array('en', 'fr', 'de', 'es_ES');
|
||||||
|
|
||||||
# SCM base configuration
|
# SCM base configuration
|
||||||
$cfg['allowed_scm'] = array('git' => 'IDF_Scm_Git',
|
$cfg['allowed_scm'] = array('git' => 'IDF_Scm_Git',
|
||||||
|
@ -74,6 +74,11 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/$#',
|
|||||||
'model' => 'IDF_Views_Project',
|
'model' => 'IDF_Views_Project',
|
||||||
'method' => 'home');
|
'method' => 'home');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/logo/$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_Project',
|
||||||
|
'method' => 'logo');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/timeline/(\w+)/$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/timeline/(\w+)/$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
'model' => 'IDF_Views_Project',
|
'model' => 'IDF_Views_Project',
|
||||||
@ -91,6 +96,23 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/feed/timeline/(\w+)/token/(.*)/$#',
|
|||||||
'method' => 'timelineFeed',
|
'method' => 'timelineFeed',
|
||||||
'name' => 'idf_project_timeline_feed_auth');
|
'name' => 'idf_project_timeline_feed_auth');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/timeline/$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_Project',
|
||||||
|
'method' => 'timelineCompat');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/feed/timeline/$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_Project',
|
||||||
|
'method' => 'timelineFeedCompat',
|
||||||
|
'name' => 'idf_project_timeline_feed');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/feed/timeline/token/(.*)/$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_Project',
|
||||||
|
'method' => 'timelineFeedCompat',
|
||||||
|
'name' => 'idf_project_timeline_feed_auth');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
'model' => 'IDF_Views_Issue',
|
'model' => 'IDF_Views_Issue',
|
||||||
@ -364,6 +386,11 @@ $ctl[] = array('regex' => '#^/api/p/([\-\w]+)/issues/create/$#',
|
|||||||
'model' => 'IDF_Views_Api',
|
'model' => 'IDF_Views_Api',
|
||||||
'method' => 'issueCreate');
|
'method' => 'issueCreate');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/api/$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_Api',
|
||||||
|
'method' => 'projectIndex');
|
||||||
|
|
||||||
// ---------- FORGE ADMIN --------------------------------
|
// ---------- FORGE ADMIN --------------------------------
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/admin/projects/$#',
|
$ctl[] = array('regex' => '#^/admin/projects/$#',
|
||||||
@ -471,6 +498,11 @@ $ctl[] = array('regex' => '#^/preferences/email/ak/(.*)/$#',
|
|||||||
'model' => 'IDF_Views_User',
|
'model' => 'IDF_Views_User',
|
||||||
'method' => 'changeEmailDo');
|
'method' => 'changeEmailDo');
|
||||||
|
|
||||||
|
$ctl[] = array('regex' => '#^/preferences/email/(\d+)/delete/$#',
|
||||||
|
'base' => $base,
|
||||||
|
'model' => 'IDF_Views_User',
|
||||||
|
'method' => 'deleteMail');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/preferences/key/(\d+)/delete/$#',
|
$ctl[] = array('regex' => '#^/preferences/key/(\d+)/delete/$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
'model' => 'IDF_Views_User',
|
'model' => 'IDF_Views_User',
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,7 @@ $m['IDF_Commit'] = array('relate_to' => array('IDF_Project', 'Pluf_User'));
|
|||||||
$m['IDF_Scm_Cache_Git'] = array('relate_to' => array('IDF_Project'));
|
$m['IDF_Scm_Cache_Git'] = array('relate_to' => array('IDF_Project'));
|
||||||
|
|
||||||
$m['IDF_UserData'] = array('relate_to' => array('Pluf_User'));
|
$m['IDF_UserData'] = array('relate_to' => array('Pluf_User'));
|
||||||
|
$m['IDF_EmailAddress'] = array('relate_to' => array('Pluf_User'));
|
||||||
|
|
||||||
Pluf_Signal::connect('Pluf_Template_Compiler::construct_template_tags_modifiers',
|
Pluf_Signal::connect('Pluf_Template_Compiler::construct_template_tags_modifiers',
|
||||||
array('IDF_Middleware', 'updateTemplateTagsModifiers'));
|
array('IDF_Middleware', 'updateTemplateTagsModifiers'));
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<form method="post" action=".">
|
<form method="post" enctype="multipart/form-data" action=".">
|
||||||
<table class="form" summary="">
|
<table class="form" summary="">
|
||||||
<tr>
|
<tr>
|
||||||
<th><strong>{$form.f.name.labelTag}:</strong></th>
|
<th><strong>{$form.f.name.labelTag}:</strong></th>
|
||||||
@ -30,6 +30,30 @@
|
|||||||
{$form.f.description|unsafe}
|
{$form.f.description|unsafe}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><strong>{trans 'Current logo'}:</strong></th>
|
||||||
|
<td>
|
||||||
|
{if $logo}
|
||||||
|
<img src="{url 'IDF_Views_Project::logo', array($project.shortname)}" alt="{trans 'Project logo'}" />
|
||||||
|
{else}
|
||||||
|
{trans 'Your project does not have a logo configured yet.'}
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><strong>{$form.f.logo.labelTag}:</strong></th>
|
||||||
|
<td>{if $form.f.logo.errors}{$form.f.logo.fieldErrors}{/if}
|
||||||
|
{$form.f.logo|unsafe}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{if $logo}
|
||||||
|
<tr>
|
||||||
|
<th><strong>{$form.f.logo_remove.labelTag}:</strong></th>
|
||||||
|
<td>{if $form.f.logo_remove.errors}{$form.f.logo_remove.fieldErrors}{/if}
|
||||||
|
{$form.f.logo_remove|unsafe}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/if}
|
||||||
<tr><td> </td>
|
<tr><td> </td>
|
||||||
<td>
|
<td>
|
||||||
<input type="submit" name="submit" value="{trans 'Save Changes'}" />
|
<input type="submit" name="submit" value="{trans 'Save Changes'}" />
|
||||||
|
@ -32,11 +32,12 @@
|
|||||||
{block extraheader}{/block}
|
{block extraheader}{/block}
|
||||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
||||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||||
|
{appversion}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="{block docid}doc3{/block}">
|
<div id="{block docid}doc3{/block}">
|
||||||
<div id="hd">
|
<div id="hd">
|
||||||
{if $project}<h1 class="project-title">{$project}</h1>{/if}
|
{if $project}<h1 class="project-title">{$project}<img class="logo" src="{url 'IDF_Views_Project::logo', array($project.shortname)}" alt="{trans 'Project logo'}" />{if $project.private}<img class="lock" src="{media '/idf/img/lock.png'}" alt="{trans 'Private project'}" />{/if}{$p}</h1>{/if}
|
||||||
{include 'idf/main-menu.html'}
|
{include 'idf/main-menu.html'}
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="main-tabs">
|
<div id="main-tabs">
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
{block extraheader}{/block}
|
{block extraheader}{/block}
|
||||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
|
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
|
||||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||||
|
{appversion}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
||||||
|
@ -32,11 +32,12 @@
|
|||||||
{block extraheader}{/block}
|
{block extraheader}{/block}
|
||||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
||||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||||
|
{appversion}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
||||||
<div id="hd">
|
<div id="hd">
|
||||||
{if $project}<h1 class="project-title">{$project}</h1>{/if}
|
{if $project}<h1 class="project-title">{$project}<img class="logo" src="{url 'IDF_Views_Project::logo', array($project.shortname)}" alt="{trans 'Project logo'}" />{if $project.private}<img class="lock" src="{media '/idf/img/lock.png'}" alt="{trans 'Private project'}" />{/if}{$p}</h1>{/if}
|
||||||
{include 'idf/main-menu.html'}
|
{include 'idf/main-menu.html'}
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="main-tabs">
|
<div id="main-tabs">
|
||||||
|
@ -9,13 +9,9 @@
|
|||||||
{/block}
|
{/block}
|
||||||
{block context}
|
{block context}
|
||||||
<p><strong>{trans 'Number of files:'}</strong> {$downloads.nb_items}</p>
|
<p><strong>{trans 'Number of files:'}</strong> {$downloads.nb_items}</p>
|
||||||
{assign $class = ''}{assign $i = 0}
|
{assign $cloud_url = 'IDF_Views_Download::listLabel'}
|
||||||
{if !$label or $label.id != $dlabel.id}
|
{assign $cloud = 'downloads'}
|
||||||
<p class="smaller">{foreach $tags as $lab}
|
{include 'idf/tags-cloud.html'}
|
||||||
{aurl 'url', 'IDF_Views_Download::listLabel', array($project.shortname, $lab.id)}
|
|
||||||
{if $class != $lab.class}{if $i != 0}<br />{/if}<strong class="label">{$lab.class}:</strong> {/if}
|
|
||||||
<a href="{$url}" class="label">{$lab.name}</a>,{assign $i = $i + 1}{assign $class = $lab.class}{/foreach}</p>
|
|
||||||
{/if}
|
|
||||||
{if $deprecated > 0}
|
{if $deprecated > 0}
|
||||||
{aurl 'url', 'IDF_Views_Download::listLabel', array($project.shortname, $dlabel.id)}
|
{aurl 'url', 'IDF_Views_Download::listLabel', array($project.shortname, $dlabel.id)}
|
||||||
<p class="helptext">{blocktrans}See <a href="{$url}">the deprecated files</a>.{/blocktrans}</p>
|
<p class="helptext">{blocktrans}See <a href="{$url}">the deprecated files</a>.{/blocktrans}</p>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<li><a href="#q-keyboard">{trans 'What are the keyboard shortcuts?'}</a></li>
|
<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>
|
<li><a href="#q-duplicate">{trans 'How to mark an issue as duplicate?'}</a></li>
|
||||||
<li><a href="#q-mugshot">{trans 'How can I display my head next to my comments?'}</a></li>
|
<li><a href="#q-mugshot">{trans 'How can I display my head next to my comments?'}</a></li>
|
||||||
<li><a href="#q-api">{trans 'What is the API and how to use it?'}</a></li>
|
<li><a href="#q-api">{trans 'What is the API and how is it used?'}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2 id="q-keyboard">{trans 'What are the keyboard shortcuts?'}</h2>
|
<h2 id="q-keyboard">{trans 'What are the keyboard shortcuts?'}</h2>
|
||||||
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
<p>{blocktrans}You need to create an account on <a href="http://en.gravatar.com/">Gravatar</a>, this takes about 5 minutes and is free.{/blocktrans}</p>
|
<p>{blocktrans}You need to create an account on <a href="http://en.gravatar.com/">Gravatar</a>, this takes about 5 minutes and is free.{/blocktrans}</p>
|
||||||
|
|
||||||
<h2 id="q-api">{trans 'What is the API and how to use it?'}</h2>
|
<h2 id="q-api">{trans 'What is the API and how is it used?'}</h2>
|
||||||
|
|
||||||
<p>{blocktrans}The API (Application Programming Interface) is used to interact with InDefero with another program. For example, this can be used to create a desktop program to submit new tickets easily.{/blocktrans}</p>{aurl 'url', 'IDF_Views::faqApi'}
|
<p>{blocktrans}The API (Application Programming Interface) is used to interact with InDefero with another program. For example, this can be used to create a desktop program to submit new tickets easily.{/blocktrans}</p>{aurl 'url', 'IDF_Views::faqApi'}
|
||||||
<p>{blocktrans}<a href="{$url}">Learn more about the API</a>.{/blocktrans}</p>
|
<p>{blocktrans}<a href="{$url}">Learn more about the API</a>.{/blocktrans}</p>
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
{block extraheader}{/block}
|
{block extraheader}{/block}
|
||||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
|
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
|
||||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||||
|
{appversion}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{extends "idf/base-simple.html"}
|
{extends "idf/base-simple.html"}
|
||||||
{block docclass}yui-t1{/block}
|
{block docclass}yui-t2{/block}
|
||||||
{block tabhome} class="active"{/block}
|
{block tabhome} class="active"{/block}
|
||||||
{block subtabs}<a href="{url 'IDF_Views::index'}" class="active">{trans 'Projects'}</a>{/block}
|
{block subtabs}<a href="{url 'IDF_Views::index'}" class="active">{trans 'Projects'}</a>{/block}
|
||||||
{block body}
|
{block body}
|
||||||
@ -9,12 +9,42 @@
|
|||||||
{aurl 'url', 'IDF_Views_Admin::projectCreate'}
|
{aurl 'url', 'IDF_Views_Admin::projectCreate'}
|
||||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'Create Project'}</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 'Create Project'}</a></p>{/if}
|
||||||
{else}
|
{else}
|
||||||
<ul>{foreach $projects as $p}
|
{foreach $projects as $p}
|
||||||
<li>{if $p.private}<img style="vertical-align: text-bottom;" src="{media '/idf/img/lock.png'}" alt="{trans 'Private project'}" /> {/if}<a href="{url 'IDF_Views_Project::home', array($p.shortname)}">{$p}</a>{if $p.shortdesc}, {$p.shortdesc}{/if}</li>
|
<div class="p-list-img">
|
||||||
{/foreach}</ul>
|
<a href="{url 'IDF_Views_Project::home', array($p.shortname)}">
|
||||||
|
<img src="{url 'IDF_Views_Project::logo', array($p.shortname)}" alt="{trans 'Project logo'}" />
|
||||||
|
</a>
|
||||||
|
{if $p.private}
|
||||||
|
<div class="p-list-private">
|
||||||
|
<a href="{url 'IDF_Views_Project::home', array($p.shortname)}">
|
||||||
|
<img style="float:right" src="{media '/idf/img/lock.png'}" alt="{trans 'Private project'}" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="p-list-prj">
|
||||||
|
<p>
|
||||||
|
<a href="{url 'IDF_Views_Project::home', array($p.shortname)}"><strong>{$p}</strong></a>
|
||||||
|
{if $p.private} - {trans 'Private project'}{/if}
|
||||||
|
</p>
|
||||||
|
<p>{$p.shortdesc}</p>
|
||||||
|
</div>
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
{/foreach}
|
||||||
{/if}
|
{/if}
|
||||||
{/block}
|
{/block}
|
||||||
{block context}
|
{block context}
|
||||||
<p><strong>{trans 'Managed Projects:'}</strong> {$projects.count()}</p>
|
<div id="stats" class="issue-submit-info">
|
||||||
|
<h3 class="a-c">{trans 'Forge statistics'}</h3>
|
||||||
|
<table>
|
||||||
|
<tr><td class="right">{trans 'Projects:'}</td><td>{$stats.projects}</td></tr>
|
||||||
|
<tr><td class="right">{trans 'Members:'}</td><td>{$stats.members}</td></tr>
|
||||||
|
<tr><td class="right">{trans 'Issues:'}</td><td>{$stats.issues}</td></tr>
|
||||||
|
<tr><td class="right">{trans 'Commits:'}</td><td>{$stats.commits}</td></tr>
|
||||||
|
<tr><td class="right">{trans 'Documentations:'}</td><td>{$stats.docpages}</td></tr>
|
||||||
|
<tr><td class="right">{trans 'Downloads:'}</td><td>{$stats.downloads}</td></tr>
|
||||||
|
<tr><td class="right">{trans 'Code reviews:'}</td><td>{$stats.reviews}</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
{block foot}<div id="branding">Powered by <a href="http://www.indefero.net" title="InDefero, bug tracking and more">InDefero</a>,<br />a <a href="http://www.ceondo.com">Céondo Ltd</a> initiative.</div>{/block}
|
{block foot}<div id="branding">Powered by <a href="http://www.indefero.net" title="InDefero, bug tracking and more">InDefero</a>,<br />a <a href="http://www.ceondo.com">Céondo Ltd</a> initiative.</div>{/block}
|
||||||
|
@ -12,9 +12,7 @@
|
|||||||
{aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')}
|
{aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')}
|
||||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
|
{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><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
|
||||||
{assign $class = ''}{assign $i = 0}
|
{assign $cloud_url = 'IDF_Views_Issue::listLabel'}
|
||||||
<p class="smaller">{foreach $project.getTagCloud($cloud) as $label}
|
{assign $cloud = 'issues'}
|
||||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
|
{include 'idf/tags-cloud.html'}
|
||||||
{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}
|
{/block}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{extends "idf/issues/base.html"}
|
{extends "idf/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" title="{if $starred}{trans 'Remove this issue from your watch list'}{else}{trans 'Add this issue to your watch list'}{/if}" /></form> {/if}{/block}
|
{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" title="{if $starred}{trans 'Remove this issue from your watch list'}{else}{trans 'Add this issue to your watch list'}{/if}" /></form> {/if}{/block}
|
||||||
{block body}
|
{block body}
|
||||||
<div style="float:right;">
|
<div class="issue-prev-next">
|
||||||
{if $previous_issue_id}
|
{if $previous_issue_id}
|
||||||
<a href="{url 'IDF_Views_Issue::view', array($project.shortname, $previous_issue_id)}" title="{if $closed}{trans 'Click here to view the previous closed issue'}{else}{trans 'Click here to view the previous open issue'}{/if}">Previous issue</a>
|
<a href="{url 'IDF_Views_Issue::view', array($project.shortname, $previous_issue_id)}" title="{if $closed}{trans 'Click here to view the previous closed issue'}{else}{trans 'Click here to view the previous open issue'}{/if}">Previous issue</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
{extends "idf/base-simple.html"}
|
{extends "idf/base-simple.html"}
|
||||||
{block docclass}yui-t1{/block}
|
{block docclass}yui-t2{/block}
|
||||||
{block body}
|
{block body}
|
||||||
<form method="post" action="{url 'IDF_Views::login'}">
|
<form method="post" action="{url 'IDF_Views::login'}">
|
||||||
<input type="hidden" name="_redirect_after" value="{$_redirect_after}" />
|
<input type="hidden" name="_redirect_after" value="{$_redirect_after}" />
|
||||||
{if $error}
|
{if $error}
|
||||||
<p class="px-message-error">{$error}</p>
|
<p class="px-message-error">{$error}</p>
|
||||||
{/if}
|
{/if}
|
||||||
<h3>{trans 'What is your login?'}</h3>
|
<h3>{trans 'What is your account information?'}</h3>
|
||||||
<p><label for="id_login">{trans 'My login is'}</label> <input type="text" name="login" id="id_login" value="{$login}" /></p>
|
<table class="form" summary="">
|
||||||
|
<tr>
|
||||||
<h3>{trans 'Do you have a password?'}</h3>
|
<th class="a-r"><strong>{trans 'My login is'}</strong></th>
|
||||||
<p><input name="action" id="action-new-user" value="new-user" type="radio" /> <label for="action-new-user">{trans 'No, I am a new here.'}</label></p>
|
<td class="a-l"><input type="text" name="login" id="id_login" value="{$login}" /></th>
|
||||||
|
</tr>
|
||||||
<p><input name="action" id="action-login" value="login" type="radio" checked="checked" /> <label for="action-login">{trans 'Yes'}</label>, <label for="id_password">{trans 'my password is'}</label> <input type="password" name="password" id="id_password" /></p>
|
<tr>
|
||||||
|
<th class="a-r"><strong>{trans 'My password is'}</strong></th>
|
||||||
|
<td class="a-l"><input type="password" name="password" id="id_password" /></th>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<p><input type="submit" value="{trans 'Sign in'}" />
|
<p><input type="submit" value="{trans 'Sign in'}" />
|
||||||
| <a href="{url 'IDF_Views::passwordRecoveryAsk'}">{trans 'I lost my password!'}</a>
|
| <a href="{url 'IDF_Views::passwordRecoveryAsk'}">{trans 'I lost my password!'}</a>
|
||||||
@ -22,3 +26,10 @@
|
|||||||
document.getElementById('id_login').focus()
|
document.getElementById('id_login').focus()
|
||||||
</script>
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
|
{block context}
|
||||||
|
<div class="issue-submit-info">
|
||||||
|
<h3>{trans 'Welcome.'}</h3>
|
||||||
|
{aurl 'url', 'IDF_Views::register', array()}
|
||||||
|
<p>{blocktrans}If you don't have an account yet, you can create one <a href="{$url}">here</a>.{/blocktrans}</a></p>
|
||||||
|
<p>{trans 'It takes less than a minute to create your account.'}</p></div>
|
||||||
|
{/block}
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
{/if}<li id="project-list"><a href="{url 'IDF_Views::index'}">{trans 'Project List'} ▾</a>
|
{/if}<li id="project-list"><a href="{url 'IDF_Views::index'}">{trans 'Project List'} ▾</a>
|
||||||
{if $allProjects.count() != 0}
|
{if $allProjects.count() != 0}
|
||||||
<ul>{foreach $allProjects as $p}
|
<ul>{foreach $allProjects as $p}
|
||||||
<li>{if $p.private}<img style="vertical-align: text-bottom;" src="{media '/idf/img/lock.png'}" alt="{trans 'Private project'}" /> {/if}
|
<li><a href="{url 'IDF_Views_Project::home', array($p.shortname)}"><img class="logo" src="{url 'IDF_Views_Project::logo', array($p.shortname)}" alt="{trans 'Project logo'}" />{if $p.private}<img class="lock" src="{media '/idf/img/lock.png'}" alt="{trans 'Private project'}" />{/if}{$p}</a></li>
|
||||||
<a href="{url 'IDF_Views_Project::home', array($p.shortname)}">{$p}</a></li>
|
|
||||||
{/foreach}</ul>
|
{/foreach}</ul>
|
||||||
{/if}</li>{if $isAdmin}<li><a href="{url 'IDF_Views_Admin::projects'}">{trans 'Forge Management'}</a></li>{/if}<li>
|
{/if}</li>{if $isAdmin}<li><a href="{url 'IDF_Views_Admin::projects'}">{trans 'Forge Management'}</a></li>{/if}<li>
|
||||||
<a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a></li>
|
<a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a></li>
|
||||||
|
@ -13,9 +13,12 @@
|
|||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block context}
|
{block context}
|
||||||
|
<p><span class="label{if 'all' == $model_filter} active{/if}"><a href="{url 'IDF_Views_Project::timeline', array($project.shortname, 'all')}">{trans 'All Updates'}</a></span></p>
|
||||||
<p><strong>{trans 'Filter by type'}</strong><br />
|
<p><strong>{trans 'Filter by type'}</strong><br />
|
||||||
{foreach $all_model_filters as $filter_key => $filter_name}
|
{foreach $accessible_model_filters as $filter_key => $filter_name}
|
||||||
|
{if $filter_key != 'all'}
|
||||||
<span class="label{if $filter_key == $model_filter} active{/if}"><a href="{url 'IDF_Views_Project::timeline', array($project.shortname, $filter_key)}">{$filter_name}</a></span><br />
|
<span class="label{if $filter_key == $model_filter} active{/if}"><a href="{url 'IDF_Views_Project::timeline', array($project.shortname, $filter_key)}">{$filter_name}</a></span><br />
|
||||||
|
{/if}
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</p>
|
</p>
|
||||||
{/block}
|
{/block}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{block body}
|
{block body}
|
||||||
{if $form.errors}
|
{if $form.errors}
|
||||||
<div class="px-message-error">
|
<div class="px-message-error">
|
||||||
<p>{trans 'Oups, please check the form for errors.'}</p>
|
<p>{trans 'Oops, please check the form for errors.'}</p>
|
||||||
{if $form.get_top_errors}
|
{if $form.get_top_errors}
|
||||||
{$form.render_top_errors|unsafe}
|
{$form.render_top_errors|unsafe}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{block body}
|
{block body}
|
||||||
{if $form.errors}
|
{if $form.errors}
|
||||||
<div class="px-message-error">
|
<div class="px-message-error">
|
||||||
<p>{trans 'Oups, please check the provided login and email address to register.'}</p>
|
<p>{trans 'Oops, please check the provided login and email address to register.'}</p>
|
||||||
{if $form.get_top_errors}
|
{if $form.get_top_errors}
|
||||||
{$form.render_top_errors|unsafe}
|
{$form.render_top_errors|unsafe}
|
||||||
{/if}
|
{/if}
|
||||||
@ -48,7 +48,8 @@
|
|||||||
{block context}
|
{block context}
|
||||||
<div class="issue-submit-info">
|
<div class="issue-submit-info">
|
||||||
<p>{trans 'Be sure to provide a valid email address, as we are sending a validation link by email.'}</p>
|
<p>{trans 'Be sure to provide a valid email address, as we are sending a validation link by email.'}</p>
|
||||||
|
{aurl 'url', 'IDF_Views::passwordRecoveryAsk'}
|
||||||
|
<p>{blocktrans}If you have just forgotten your login information, then there is no need to create a new account. Just go <a href="{$url}">here</a> to recover your login name and password.{/blocktrans}</p>
|
||||||
<p><strong>{trans 'Did you know?'}</strong><br />
|
<p><strong>{trans 'Did you know?'}</strong><br />
|
||||||
{aurl 'url', 'IDF_Views::faq'}
|
{aurl 'url', 'IDF_Views::faq'}
|
||||||
{blocktrans}With your account, you will able to participate in the life of all the projects hosted here. Participating in a software project must be fun, so if you have troubles, you can <a href="{$url}">let us know about your issues at anytime</a>!{/blocktrans}</p>
|
{blocktrans}With your account, you will able to participate in the life of all the projects hosted here. Participating in a software project must be fun, so if you have troubles, you can <a href="{$url}">let us know about your issues at anytime</a>!{/blocktrans}</p>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{block body}
|
{block body}
|
||||||
{if $form.errors}
|
{if $form.errors}
|
||||||
<div class="px-message-error">
|
<div class="px-message-error">
|
||||||
<p>{trans 'Oups, we found an error in the form.'}</p>
|
<p>{trans 'Oops, we found an error in the form.'}</p>
|
||||||
{if $form.get_top_errors}
|
{if $form.get_top_errors}
|
||||||
{$form.render_top_errors|unsafe}
|
{$form.render_top_errors|unsafe}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li>A commit or revision of the current code in the repository from which you started your work.</li>
|
<li>A commit or revision of the current code in the repository from which you started your work.</li>
|
||||||
<li>A patch describing your changes with respect to the reference commit.</li>
|
<li>A patch describing your changes with respect to the reference commit.</li>
|
||||||
<li><strong>Ensure your patch does not contain any passwords or confidential information!</strong></li>
|
<li><strong>Check your patch does not provide any password or confidential information!</strong></li>
|
||||||
</ul>{/blocktrans}
|
</ul>{/blocktrans}
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th><strong>{trans 'Author:'}</strong></th><td>{showuser $rcommit.get_author(), $request, $cobject.author}</td>
|
<th><strong>{trans 'Author:'}</strong></th><td>{showuser $rcommit.get_author(), $request, $cobject.author}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
{if $cobject.branch}<tr>
|
||||||
<th><strong>{trans 'Branch:'}</strong></th><td>{$cobject.branch}</td>
|
<th><strong>{trans 'Branch:'}</strong></th><td>{$cobject.branch}</td>
|
||||||
</tr>
|
</tr>{/if}
|
||||||
<tr>
|
<tr>
|
||||||
<th><strong>{trans 'Commit:'}</strong></th><td class="mono"><a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $commit)}" title="{trans 'View corresponding source tree'}">{$cobject.commit}</a></td>
|
<th><strong>{trans 'Commit:'}</strong></th><td class="mono"><a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $commit)}" title="{trans 'View corresponding source tree'}">{$cobject.commit}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -23,7 +23,7 @@
|
|||||||
</tr>{/if}
|
</tr>{/if}
|
||||||
<tr>
|
<tr>
|
||||||
<th><strong>{trans 'Message:'}</strong></th><td>{issuetext $cobject.title, $request}{if isset($cobject.full_message)}<br/><br/>{issuetext $cobject.full_message, $request, true, false, true, true, true}{/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, true, false, true, true, true}{/if}</td>
|
||||||
</tr>{if count($changes)}
|
</tr>{if count($cobject.parents) < 2 and count($changes)}
|
||||||
<tr>
|
<tr>
|
||||||
<th><strong>{trans 'Changes:'}</strong></th>
|
<th><strong>{trans 'Changes:'}</strong></th>
|
||||||
<td>
|
<td>
|
||||||
@ -38,8 +38,7 @@
|
|||||||
<tr><td><span class="scm-action added" title="{trans 'added'}">A</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{trans 'full'}</a>){/if}</td></tr>
|
<tr><td><span class="scm-action added" title="{trans 'added'}">A</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{trans 'full'}</a>){/if}</td></tr>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
{foreach $changes.patches as $filename}
|
{foreach $changes.patches as $filename}
|
||||||
{assign $ndiff = count($diff.files[$filename]['chunks'])}
|
<tr><td><span class="scm-action patched" title="{trans 'modified'}">M</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])}{assign $ndiff = count($diff.files[$filename]['chunks'])} (<a href="#diff-{$filename|md5}">{blocktrans $ndiff}{$ndiff} diff{plural}{$ndiff} diffs{/blocktrans}</a>){/if}</td></tr>
|
||||||
<tr><td><span class="scm-action patched" title="{trans 'modified'}">M</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{blocktrans $ndiff}{$ndiff} diff{plural}{$ndiff} diffs{/blocktrans}</a>){/if}</td></tr>
|
|
||||||
{/foreach}
|
{/foreach}
|
||||||
{foreach $changes.properties as $filename => $properties}
|
{foreach $changes.properties as $filename => $properties}
|
||||||
<tr><td><span class="scm-action property-changed" title="{trans 'properies changed'}">P</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>
|
<tr><td><span class="scm-action property-changed" title="{trans 'properies changed'}">P</span></td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>
|
||||||
@ -61,11 +60,13 @@
|
|||||||
</tr>{/if} {* End of the if count($changes) *}
|
</tr>{/if} {* End of the if count($changes) *}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{if count($diff.files)}
|
{if count($cobject.parents) < 2 and count($diff.files)}
|
||||||
<h2>{trans 'File differences'}</h2>
|
<h2>{trans 'File differences'}</h2>
|
||||||
|
|
||||||
{$diff.as_html()}
|
{$diff.as_html()}
|
||||||
{/if}{if count($diff.files) or $large_commit}
|
{/if}
|
||||||
|
|
||||||
|
{if count($cobject.parents) < 2 and (count($diff.files) or $large_commit)}
|
||||||
{aurl 'url', 'IDF_Views_Source::downloadDiff', array($project.shortname, $commit)}
|
{aurl 'url', 'IDF_Views_Source::downloadDiff', 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 the corresponding diff file'}</a></p>
|
<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 the corresponding diff file'}</a></p>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -11,7 +11,7 @@ code.{/blocktrans}</p>
|
|||||||
<p><kbd>git clone {$project.getSourceAccessUrl($user)}</kbd></p>
|
<p><kbd>git clone {$project.getSourceAccessUrl($user)}</kbd></p>
|
||||||
|
|
||||||
{aurl 'url', 'IDF_Views_User::myAccount'}
|
{aurl 'url', 'IDF_Views_User::myAccount'}
|
||||||
<p>{blocktrans}You may need to <a href="{$url}">provide your SSH key</a>. The synchronization of your SSH key can take a couple of minutes. You can learn more about <a href="http://www.google.com/search?q=public+ssh+key+authentication">SSH key authentification</a>.{/blocktrans}</p>
|
<p>{blocktrans}You may need to <a href="{$url}">provide your SSH key</a>. The synchronization of your SSH key can take a couple of minutes. You can learn more about <a href="http://www.google.com/search?q=public+ssh+key+authentication">SSH key authentication</a>.{/blocktrans}</p>
|
||||||
|
|
||||||
{if $isOwner or $isMember}
|
{if $isOwner or $isMember}
|
||||||
<h3>{trans 'First Commit'}</h3>
|
<h3>{trans 'First Commit'}</h3>
|
||||||
|
@ -2,9 +2,19 @@
|
|||||||
{block docclass}yui-t2{assign $inError=true}{/block}
|
{block docclass}yui-t2{assign $inError=true}{/block}
|
||||||
{block body}
|
{block body}
|
||||||
|
|
||||||
<p>{blocktrans}The revision <b>{$commit}</b> is not valid or does not exist
|
<p>{blocktrans}The branch or revision <b>{$commit}</b> is not valid or does not exist
|
||||||
in this repository.{/blocktrans}</p>
|
in this repository.{/blocktrans}</p>
|
||||||
|
|
||||||
|
<p>{blocktrans}The following list shows all available branches:{/blocktrans}</p>
|
||||||
|
<ul>
|
||||||
|
{foreach $branches as $branch => $path}
|
||||||
|
{aurl 'url', 'IDF_Views_Source::treeBase', array($project.shortname, $branch)}
|
||||||
|
<li class="label">
|
||||||
|
<a href="{$url}" class="label">{if $path}{$path}{else}{$branch}{/if}</a>
|
||||||
|
</li>
|
||||||
|
{/foreach}
|
||||||
|
</ul>
|
||||||
|
|
||||||
{if $isOwner or $isMember}
|
{if $isOwner or $isMember}
|
||||||
{aurl 'url', 'IDF_Views_Source::help', array($project.shortname)}
|
{aurl 'url', 'IDF_Views_Source::help', array($project.shortname)}
|
||||||
<p>{blocktrans}If this is a new repository, the reason for this error
|
<p>{blocktrans}If this is a new repository, the reason for this error
|
||||||
|
8
src/IDF/templates/idf/tags-cloud.html
Normal file
8
src/IDF/templates/idf/tags-cloud.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{assign $class = ''}{assign $i = 0}
|
||||||
|
<div id="tagscloud" class="smaller"><dl>{foreach $project.getTagCloud($cloud) as $label}
|
||||||
|
{aurl 'url', $cloud_url, array($project.shortname, $label.id, 'open')}
|
||||||
|
{if $class != $label.class}<dt class="label">{$label.class}</dt>{assign $i = 0}{/if}
|
||||||
|
<dd><a href="{$url}" class="label">{$label.name},</a></dd>
|
||||||
|
{assign $class = $label.class}
|
||||||
|
{assign $i = $i + 1}
|
||||||
|
{/foreach}</dl></p>
|
@ -2,7 +2,7 @@
|
|||||||
{block body}
|
{block body}
|
||||||
{if $form.errors}
|
{if $form.errors}
|
||||||
<div class="px-message-error">
|
<div class="px-message-error">
|
||||||
<p>{trans 'Oups, we found an error in the form.'}</p>
|
<p>{trans 'Oops, we found an error in the form.'}</p>
|
||||||
{if $form.get_top_errors}
|
{if $form.get_top_errors}
|
||||||
{$form.render_top_errors|unsafe}
|
{$form.render_top_errors|unsafe}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{block body}
|
{block body}
|
||||||
{if $form.errors}
|
{if $form.errors}
|
||||||
<div class="px-message-error">
|
<div class="px-message-error">
|
||||||
<p>{trans 'Oups, please check the form for errors.'}</p>
|
<p>{trans 'Oops, please check the form for errors.'}</p>
|
||||||
{if $form.get_top_errors}
|
{if $form.get_top_errors}
|
||||||
{$form.render_top_errors|unsafe}
|
{$form.render_top_errors|unsafe}
|
||||||
{/if}
|
{/if}
|
||||||
@ -100,6 +100,14 @@
|
|||||||
<span class="helptext">{$form.f.public_key.help_text}</span>
|
<span class="helptext">{$form.f.public_key.help_text}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr><td colspan="2" class="separator">{trans "Secondary Emails"}</td></tr>
|
||||||
|
<tr>
|
||||||
|
<th>{$form.f.secondary_mail.labelTag}:</th>
|
||||||
|
<td>{if $form.f.secondary_mail.errors}{$form.f.secondary_mail.fieldErrors}{/if}
|
||||||
|
{$form.f.secondary_mail|unsafe}<br />
|
||||||
|
<span class="helptext">{$form.f.secondary_mail.help_text}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr class="pass-info" id="extra-password">
|
<tr class="pass-info" id="extra-password">
|
||||||
<th>{trans 'Extra password'}:</th>
|
<th>{trans 'Extra password'}:</th>
|
||||||
<td><span class="mono">{$ext_pass}</span><br />
|
<td><span class="mono">{$ext_pass}</span><br />
|
||||||
@ -129,6 +137,15 @@
|
|||||||
</tr>{/foreach}
|
</tr>{/foreach}
|
||||||
</table>
|
</table>
|
||||||
{/if}
|
{/if}
|
||||||
|
{if count($mailaddrs)>1}
|
||||||
|
<table summary=" " class="recent-issues">
|
||||||
|
<tr><th colspan="2">{trans 'Your additional email addresses'}</th></tr>
|
||||||
|
{foreach $mailaddrs as $mail}{if $mail.id != -1}<tr><td>
|
||||||
|
{$mail.address}</td><td> <form class="star" method="post" action="{url 'IDF_Views_User::deleteMail', array($mail.id)}"><input type="image" src="{media '/idf/img/trash.png'}" name="submit" value="{trans 'Delete this address'}" /></form>
|
||||||
|
</td>
|
||||||
|
</tr>{/if}{/foreach}
|
||||||
|
</table>
|
||||||
|
{/if}
|
||||||
{/block}
|
{/block}
|
||||||
{block context}
|
{block context}
|
||||||
<div class="issue-submit-info">
|
<div class="issue-submit-info">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{block body}
|
{block body}
|
||||||
{if $form.errors}
|
{if $form.errors}
|
||||||
<div class="px-message-error">
|
<div class="px-message-error">
|
||||||
<p>{trans 'Oups, please check the provided login or email address to recover your password.'}</p>
|
<p>{trans 'Oops, please check the provided login or email address to recover your password.'}</p>
|
||||||
{if $form.get_top_errors}
|
{if $form.get_top_errors}
|
||||||
{$form.render_top_errors|unsafe}
|
{$form.render_top_errors|unsafe}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{block body}
|
{block body}
|
||||||
{if $form.errors}
|
{if $form.errors}
|
||||||
<div class="px-message-error">
|
<div class="px-message-error">
|
||||||
<p>{trans 'Oups, we found an error in the form.'}</p>
|
<p>{trans 'Oops, we found an error in the form.'}</p>
|
||||||
{if $form.get_top_errors}
|
{if $form.get_top_errors}
|
||||||
{$form.render_top_errors|unsafe}
|
{$form.render_top_errors|unsafe}
|
||||||
{/if}
|
{/if}
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<div class="issue-submit-info">
|
<div class="issue-submit-info">
|
||||||
<h2>{trans 'Instructions'}</h2>
|
<h2>{trans 'Instructions'}</h2>
|
||||||
<p>{trans 'Use your email software to read your emails and open your verification email. Either click directly on the verification link or copy/paste the verification key in the box and submit the form.'}</p>
|
<p>{trans 'Use your email software to read your emails and open your verification email. Either click directly on the verification link or copy/paste the verification key in the box and submit the form.'}</p>
|
||||||
<p>{trans 'Just after providing the confirmation key, you will be able to reset your password and use again this website fully.'}</p>
|
<p>{trans 'Just after providing the confirmation key, you will be able to reset your password and use this website fully.'}</p>
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
{block javascript}<script type="text/javascript">
|
{block javascript}<script type="text/javascript">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{block body}
|
{block body}
|
||||||
{if $form.errors}
|
{if $form.errors}
|
||||||
<div class="px-message-error">
|
<div class="px-message-error">
|
||||||
<p>{trans 'Oups, please check the form for errors.'}</p>
|
<p>{trans 'Oops, please check the form for errors.'}</p>
|
||||||
{if $form.get_top_errors}
|
{if $form.get_top_errors}
|
||||||
{$form.render_top_errors|unsafe}
|
{$form.render_top_errors|unsafe}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -9,13 +9,9 @@
|
|||||||
{/block}
|
{/block}
|
||||||
{block context}
|
{block context}
|
||||||
<p><strong>{trans 'Number of pages:'}</strong> {$pages.nb_items}</p>
|
<p><strong>{trans 'Number of pages:'}</strong> {$pages.nb_items}</p>
|
||||||
{assign $class = ''}{assign $i = 0}
|
{assign $cloud_url = 'IDF_Views_Wiki::listLabel'}
|
||||||
{if !$label or $label.id != $dlabel.id}
|
{assign $cloud = 'wiki'}
|
||||||
<p class="smaller">{foreach $tags as $lab}
|
{include 'idf/tags-cloud.html'}
|
||||||
{aurl 'url', 'IDF_Views_Wiki::listLabel', array($project.shortname, $lab.id)}
|
|
||||||
{if $class != $lab.class}{if $i != 0}<br />{/if}<strong class="label">{$lab.class}:</strong> {/if}
|
|
||||||
<a href="{$url}" class="label">{$lab.name}</a>,{assign $i = $i + 1}{assign $class = $lab.class}{/foreach}</p>
|
|
||||||
{/if}
|
|
||||||
{if $deprecated > 0}
|
{if $deprecated > 0}
|
||||||
{aurl 'url', 'IDF_Views_Wiki::listLabel', array($project.shortname, $dlabel.id)}
|
{aurl 'url', 'IDF_Views_Wiki::listLabel', array($project.shortname, $dlabel.id)}
|
||||||
<p class="helptext">{blocktrans}See <a href="{$url}">the deprecated pages</a>.{/blocktrans}</p>
|
<p class="helptext">{blocktrans}See <a href="{$url}">the deprecated pages</a>.{/blocktrans}</p>
|
||||||
|
5
src/IDF/version.php
Normal file
5
src/IDF/version.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
return array(
|
||||||
|
'version' => '1.2-dev',
|
||||||
|
'revision' => '$Format:%H$',
|
||||||
|
);
|
51
test/IDF/DiffTest.php
Normal file
51
test/IDF/DiffTest.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?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) 2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
include 'IDF/Diff.php';
|
||||||
|
|
||||||
|
class IDF_DiffTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testParse()
|
||||||
|
{
|
||||||
|
$datadir = DATADIR.'/'.__CLASS__;
|
||||||
|
|
||||||
|
foreach (glob($datadir.'/*.diff') as $difffile)
|
||||||
|
{
|
||||||
|
$diffprefix = 0;
|
||||||
|
if (strpos($difffile, '-git-') != false || strpos($difffile, '-hg-') != false)
|
||||||
|
{
|
||||||
|
$diffprefix = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$expectedfile = str_replace('.diff', '.expected', $difffile);
|
||||||
|
$expectedcontent = @file_get_contents($expectedfile);
|
||||||
|
|
||||||
|
$diffcontent = file_get_contents($difffile);
|
||||||
|
$diff = new IDF_Diff($diffcontent, $diffprefix);
|
||||||
|
$this->assertEquals(unserialize($expectedcontent),
|
||||||
|
$diff->parse(),
|
||||||
|
'parsed diff '.$difffile.' does not match');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
176
test/IDF/Scm/Monotone/BasicIOTest.php
Normal file
176
test/IDF/Scm/Monotone/BasicIOTest.php
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
<?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) 2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
include 'IDF/Scm/Monotone/BasicIO.php';
|
||||||
|
|
||||||
|
class IDF_Scm_Monotone_BasicIOTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testParse()
|
||||||
|
{
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse(null);
|
||||||
|
$this->assertTrue(is_array($stanzas) && count($stanzas) == 0);
|
||||||
|
|
||||||
|
// single stanza, single line, only key
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse('foo');
|
||||||
|
$this->assertEquals(1, count($stanzas));
|
||||||
|
$stanza = $stanzas[0];
|
||||||
|
$this->assertEquals(1, count($stanza));
|
||||||
|
$entry = $stanza[0];
|
||||||
|
$this->assertEquals('foo', $entry['key']);
|
||||||
|
$this->assertTrue(!array_key_exists('hash', $entry));
|
||||||
|
$this->assertTrue(!array_key_exists('values', $entry));
|
||||||
|
|
||||||
|
// single stanza, single line, key with hash
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse("foo [0123456789012345678901234567890123456789]");
|
||||||
|
$this->assertEquals(1, count($stanzas));
|
||||||
|
$stanza = $stanzas[0];
|
||||||
|
$this->assertEquals(1, count($stanza));
|
||||||
|
$entry = $stanza[0];
|
||||||
|
$this->assertEquals('foo', $entry['key']);
|
||||||
|
$this->assertEquals("0123456789012345678901234567890123456789", $entry['hash']);
|
||||||
|
$this->assertTrue(!array_key_exists('values', $entry));
|
||||||
|
|
||||||
|
// single stanza, single line, key with two values
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse("foo \"bar\n\nbaz\" \"bla\"");
|
||||||
|
$this->assertEquals(1, count($stanzas));
|
||||||
|
$stanza = $stanzas[0];
|
||||||
|
$this->assertEquals(1, count($stanza));
|
||||||
|
$entry = $stanza[0];
|
||||||
|
$this->assertEquals('foo', $entry['key']);
|
||||||
|
$this->assertTrue(!array_key_exists('hash', $entry));
|
||||||
|
$this->assertEquals(array("bar\n\nbaz", "bla"), $entry['values']);
|
||||||
|
|
||||||
|
// single stanza, single line, key with a value and a hash
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse("foo \"bar\n\nbaz\" [0123456789012345678901234567890123456789]");
|
||||||
|
$this->assertEquals(1, count($stanzas));
|
||||||
|
$stanza = $stanzas[0];
|
||||||
|
$this->assertEquals(1, count($stanza));
|
||||||
|
$entry = $stanza[0];
|
||||||
|
$this->assertEquals('foo', $entry['key']);
|
||||||
|
$this->assertTrue(!array_key_exists('hash', $entry));
|
||||||
|
$this->assertEquals(array("bar\n\nbaz", "0123456789012345678901234567890123456789"), $entry['values']);
|
||||||
|
|
||||||
|
// single stanza, two lines, keys with single value / hash
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse("foo \"bar\"\nbaz [0123456789012345678901234567890123456789]");
|
||||||
|
$this->assertEquals(1, count($stanzas));
|
||||||
|
$stanza = $stanzas[0];
|
||||||
|
$this->assertEquals(2, count($stanza));
|
||||||
|
$entry = $stanza[0];
|
||||||
|
$this->assertEquals('foo', $entry['key']);
|
||||||
|
$this->assertTrue(!array_key_exists('hash', $entry));
|
||||||
|
$this->assertEquals(array("bar"), $entry['values']);
|
||||||
|
$entry = $stanza[1];
|
||||||
|
$this->assertEquals('baz', $entry['key']);
|
||||||
|
$this->assertTrue(!array_key_exists('values', $entry));
|
||||||
|
$this->assertEquals("0123456789012345678901234567890123456789", $entry['hash']);
|
||||||
|
|
||||||
|
// two stanza, one two liner, one one liner
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse("foo \"bar\"\nbaz [0123456789012345678901234567890123456789]\n\nbla \"blub\"");
|
||||||
|
$this->assertEquals(2, count($stanzas));
|
||||||
|
$stanza = $stanzas[0];
|
||||||
|
$this->assertEquals(2, count($stanza));
|
||||||
|
$entry = $stanza[0];
|
||||||
|
$this->assertEquals('foo', $entry['key']);
|
||||||
|
$this->assertTrue(!array_key_exists('hash', $entry));
|
||||||
|
$this->assertEquals(array("bar"), $entry['values']);
|
||||||
|
$entry = $stanza[1];
|
||||||
|
$this->assertEquals('baz', $entry['key']);
|
||||||
|
$this->assertTrue(!array_key_exists('values', $entry));
|
||||||
|
$this->assertEquals("0123456789012345678901234567890123456789", $entry['hash']);
|
||||||
|
$stanza = $stanzas[1];
|
||||||
|
$this->assertEquals(1, count($stanza));
|
||||||
|
$entry = $stanza[0];
|
||||||
|
$this->assertEquals('bla', $entry['key']);
|
||||||
|
$this->assertTrue(!array_key_exists('hash', $entry));
|
||||||
|
$this->assertEquals(array("blub"), $entry['values']);
|
||||||
|
|
||||||
|
// (un)escaping tests
|
||||||
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse('foo "bar\\baz" "bla\"blub"');
|
||||||
|
$this->assertEquals(1, count($stanzas));
|
||||||
|
$stanza = $stanzas[0];
|
||||||
|
$this->assertEquals(1, count($stanza));
|
||||||
|
$entry = $stanza[0];
|
||||||
|
$this->assertEquals('foo', $entry['key']);
|
||||||
|
$this->assertTrue(!array_key_exists('hash', $entry));
|
||||||
|
$this->assertEquals(array('bar\baz', 'bla"blub'), $entry['values']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCompile()
|
||||||
|
{
|
||||||
|
$stanzas = array(
|
||||||
|
array(
|
||||||
|
array('key' => 'foo'),
|
||||||
|
array('key' => 'bar', 'values' => array('one', "two\nthree")),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
array('key' => 'baz', 'hash' => '0123456789012345678901234567890123456789'),
|
||||||
|
array('key' => 'blablub', 'values' => array('one"two', 'three\four')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$ex =<<<END
|
||||||
|
foo
|
||||||
|
bar "one" "two
|
||||||
|
three"
|
||||||
|
|
||||||
|
baz [0123456789012345678901234567890123456789]
|
||||||
|
blablub "one\"two" "three\\\\four"
|
||||||
|
|
||||||
|
END;
|
||||||
|
$this->assertEquals($ex, IDF_Scm_Monotone_BasicIO::compile($stanzas));
|
||||||
|
|
||||||
|
// keys must not be null
|
||||||
|
$stanzas = array(
|
||||||
|
array(
|
||||||
|
array('key' => null, 'values' => array('foo')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$thrown = false;
|
||||||
|
try {
|
||||||
|
IDF_Scm_Monotone_BasicIO::compile($stanzas);
|
||||||
|
} catch (IDF_Scm_Exception $e) {
|
||||||
|
$this->assertRegExp('/^"key" not found in basicio stanza/', $e->getMessage());
|
||||||
|
$thrown = true;
|
||||||
|
}
|
||||||
|
$this->assertTrue($thrown);
|
||||||
|
|
||||||
|
// ...nor completly non-existing
|
||||||
|
$stanzas = array(
|
||||||
|
array(
|
||||||
|
array('values' => array('foo')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$thrown = false;
|
||||||
|
try {
|
||||||
|
IDF_Scm_Monotone_BasicIO::compile($stanzas);
|
||||||
|
} catch (IDF_Scm_Exception $e) {
|
||||||
|
$this->assertRegExp('/^"key" not found in basicio stanza/', $e->getMessage());
|
||||||
|
$thrown = true;
|
||||||
|
}
|
||||||
|
$this->assertTrue($thrown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
161
test/IDF/Scm/Monotone/ZipRenderTest.php
Normal file
161
test/IDF/Scm/Monotone/ZipRenderTest.php
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
<?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) 2011 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
require_once 'IDF/Scm/Monotone/ZipRender.php';
|
||||||
|
require_once 'IDF/Scm/Monotone/IStdio.php';
|
||||||
|
|
||||||
|
class ZipRenderStdioMock implements IDF_Scm_Monotone_IStdio
|
||||||
|
{
|
||||||
|
// unused
|
||||||
|
public function __construct(IDF_Project $project) {}
|
||||||
|
|
||||||
|
// unused
|
||||||
|
public function start() {}
|
||||||
|
|
||||||
|
// unused
|
||||||
|
public function stop() {}
|
||||||
|
|
||||||
|
public function exec(array $args, array $options = array())
|
||||||
|
{
|
||||||
|
if ($args[0] == 'certs') {
|
||||||
|
$basicio =<<<END
|
||||||
|
key [0504aea5d3716d31281171aaecf3a7c227e5545b]
|
||||||
|
signature "ok"
|
||||||
|
name "author"
|
||||||
|
value "joe@home"
|
||||||
|
trust "trusted"
|
||||||
|
|
||||||
|
key [0504aea5d3716d31281171aaecf3a7c227e5545b]
|
||||||
|
signature "ok"
|
||||||
|
name "branch"
|
||||||
|
value "foo"
|
||||||
|
trust "trusted"
|
||||||
|
|
||||||
|
key [0504aea5d3716d31281171aaecf3a7c227e5545b]
|
||||||
|
signature "ok"
|
||||||
|
name "changelog"
|
||||||
|
value "test"
|
||||||
|
trust "trusted"
|
||||||
|
|
||||||
|
key [0504aea5d3716d31281171aaecf3a7c227e5545b]
|
||||||
|
signature "ok"
|
||||||
|
name "date"
|
||||||
|
value "2009-07-06T22:06:27"
|
||||||
|
trust "trusted"
|
||||||
|
|
||||||
|
END;
|
||||||
|
return $basicio;
|
||||||
|
}
|
||||||
|
if ($args[0] == 'get_manifest_of') {
|
||||||
|
$basicio =<<<END
|
||||||
|
format_version "1"
|
||||||
|
|
||||||
|
dir ""
|
||||||
|
|
||||||
|
file "foo"
|
||||||
|
content [6fcf9dfbd479ed82697fee719b9f8c610a11ff2a]
|
||||||
|
|
||||||
|
dir "bar"
|
||||||
|
|
||||||
|
file "bar/baz"
|
||||||
|
content [9063a9f0e032b6239403b719cbbba56ac4e4e45f]
|
||||||
|
|
||||||
|
END;
|
||||||
|
return $basicio;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($args[0] == 'get_file') {
|
||||||
|
if ($args[1] == '6fcf9dfbd479ed82697fee719b9f8c610a11ff2a') {
|
||||||
|
return 'This is foo.';
|
||||||
|
}
|
||||||
|
if ($args[1] == '9063a9f0e032b6239403b719cbbba56ac4e4e45f') {
|
||||||
|
return 'This is baz.';
|
||||||
|
}
|
||||||
|
throw new Exception('unexpected id ' . $args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception('unexpected command ' . $args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unused
|
||||||
|
public function getLastOutOfBandOutput() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IDF_Scm_Monotone_ZipRenderTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
// we can not test header sending with PHP-CLI, as header() is ignored
|
||||||
|
// in this environment
|
||||||
|
public function testRender()
|
||||||
|
{
|
||||||
|
$mock = new ZipRenderStdioMock(new IDF_Project());
|
||||||
|
$renderer = new IDF_Scm_Monotone_ZipRender($mock, '97fee719b9f8c610a11ff2a9063a9f0e032b6');
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$renderer->render(true);
|
||||||
|
$zipcontents = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
// for this version php needs to be compiled with --enable-zip
|
||||||
|
if (function_exists('zip_open')) {
|
||||||
|
// yes, I'd rather have used php://memory here, but ZipArchive::open()
|
||||||
|
// complained that it could not open the stream in question
|
||||||
|
$filename = tempnam(Pluf::f('tmp_folder', '/tmp'), __CLASS__.'.');
|
||||||
|
file_put_contents($filename, $zipcontents);
|
||||||
|
|
||||||
|
$za = new ZipArchive();
|
||||||
|
$za->open($filename);
|
||||||
|
$this->assertEquals(2, $za->numFiles);
|
||||||
|
|
||||||
|
// 2009-07-06T22:06:27 - one second
|
||||||
|
// (don't ask me why, seems to be some quirk in zipstream)
|
||||||
|
$mtime = 1246910787 - 1;
|
||||||
|
|
||||||
|
// foo
|
||||||
|
$data = $za->statIndex(0);
|
||||||
|
$this->assertEquals('foo', $data['name']);
|
||||||
|
$this->assertEquals(12, $data['size']);
|
||||||
|
$this->assertEquals($mtime, $data['mtime']);
|
||||||
|
|
||||||
|
// bar/baz
|
||||||
|
$data = $za->statIndex(1);
|
||||||
|
$this->assertEquals('bar/baz', $data['name']);
|
||||||
|
$this->assertEquals(12, $data['size']);
|
||||||
|
$this->assertEquals($mtime, $data['mtime']);
|
||||||
|
|
||||||
|
$za->close();
|
||||||
|
unlink($filename);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$wrapped_act = wordwrap(
|
||||||
|
base64_encode($zipcontents),
|
||||||
|
32, "\n", true
|
||||||
|
);
|
||||||
|
$wrapped_exp = wordwrap(
|
||||||
|
base64_encode(file_get_contents(DATADIR . '/' . __CLASS__ . '/data.zip')),
|
||||||
|
32, "\n", true
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($wrapped_exp, $wrapped_act);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
test/bootstrap.php
Normal file
27
test/bootstrap.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$config_file = dirname(__FILE__) . '/config.php';
|
||||||
|
if (!file_exists($config_file)) {
|
||||||
|
die("'test/config.php' does not exist\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
echo ">>> setting paths...\n";
|
||||||
|
define('SRCDIR', realpath(dirname(__FILE__) . '/../src'));
|
||||||
|
define('TESTDIR', dirname(__FILE__));
|
||||||
|
define('DATADIR', TESTDIR . '/data');
|
||||||
|
set_include_path(get_include_path() . PATH_SEPARATOR . SRCDIR);
|
||||||
|
|
||||||
|
$testconfig = require_once $config_file;
|
||||||
|
if (file_exists($testconfig['db_database'])) {
|
||||||
|
echo ">>> removing any existing database\n";
|
||||||
|
unlink($testconfig['db_database']);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo ">>> creating empty test database...\n";
|
||||||
|
passthru('php ' . PLUF_PATH . '/migrate.php --conf=' . TESTDIR . '/config.php -a -i');
|
||||||
|
|
||||||
|
echo ">>> setting up web application...\n";
|
||||||
|
require 'Pluf.php';
|
||||||
|
// for PHPUnit 3.5 and beyond this is needed, since it comes with its own class loader
|
||||||
|
spl_autoload_register('__autoload');
|
||||||
|
Pluf::start(TESTDIR . '/config.php');
|
95
test/config.php-dist
Normal file
95
test/config.php-dist
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This is a basic test configuration file for unit tests. It mimics most of
|
||||||
|
* the defaults from IDF/conf/idf.php-dist, but sets up a local sqlite database
|
||||||
|
* which is purged before each test run and uses a different temporary file
|
||||||
|
* directory.
|
||||||
|
*
|
||||||
|
* You can keep most of these settings as is, but ensure that you set up
|
||||||
|
* 'pear_path' at least, otherwise you'll get strange errors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once dirname(__FILE__).'/../src/IDF/conf/path.php';
|
||||||
|
|
||||||
|
$cfg = array();
|
||||||
|
$cfg['debug'] = true;
|
||||||
|
$cfg['debug_scm'] = true;
|
||||||
|
$cfg['git_repositories'] = '/home/git/repositories/%s.git';
|
||||||
|
$cfg['git_remote_url'] = 'git://localhost/%s.git';
|
||||||
|
$cfg['git_write_remote_url'] = 'git@localhost:%s.git';
|
||||||
|
$cfg['svn_repositories'] = 'file:///home/svn/repositories/%s';
|
||||||
|
$cfg['svn_remote_url'] = 'http://localhost/svn/%s';
|
||||||
|
$cfg['mtn_path'] = 'mtn';
|
||||||
|
$cfg['mtn_opts'] = array('--no-workspace', '--no-standard-rcfiles');
|
||||||
|
$cfg['mtn_repositories'] = '/home/mtn/repositories/%s.mtn';
|
||||||
|
$cfg['mtn_remote_url'] = 'mtn://my-host.biz/%s';
|
||||||
|
$cfg['mtn_db_access'] = 'local';
|
||||||
|
#$cfg['mtn_confdir'] = '/path/to/dir/tree/';
|
||||||
|
#$cfg['mtn_confdir_extra'] = array('hooks.d/something.lua')
|
||||||
|
#$cfg['mtn_usher_conf'] = '/path/to/usher.conf';
|
||||||
|
$cfg['mercurial_repositories'] = '/home/mercurial/repositories/%s';
|
||||||
|
#$cfg['mercurial_remote_url'] = 'http://projects.ceondo.com/hg/%s';
|
||||||
|
$cfg['admins'] = array(array('Admin', 'you@example.com'),);
|
||||||
|
$cfg['send_emails'] = true;
|
||||||
|
$cfg['mail_backend'] = 'smtp';
|
||||||
|
$cfg['mail_host'] = 'localhost';
|
||||||
|
$cfg['mail_port'] = 25;
|
||||||
|
$cfg['idf_base'] = '/index.php';
|
||||||
|
$cfg['url_base'] = 'http://localhost';
|
||||||
|
$cfg['url_media'] = 'http://localhost/media';
|
||||||
|
$cfg['url_upload'] = 'http://localhost/media/upload';
|
||||||
|
$cfg['upload_path'] = '/home/www/indefero/www/media/upload';
|
||||||
|
$cfg['upload_issue_path'] = '/home/www/indefero/attachments';
|
||||||
|
$cfg['secret_key'] = '';
|
||||||
|
$cfg['from_email'] = 'sender@example.com';
|
||||||
|
$cfg['bounce_email'] = 'no-reply@example.com';
|
||||||
|
$cfg['tmp_folder'] = dirname(__FILE__) . '/tmp';
|
||||||
|
$cfg['db_login'] = 'www';
|
||||||
|
$cfg['db_password'] = '';
|
||||||
|
$cfg['db_server'] = '';
|
||||||
|
$cfg['db_version'] = '5.1';
|
||||||
|
$cfg['db_table_prefix'] = 'indefero_';
|
||||||
|
$cfg['db_engine'] = 'SQLite';
|
||||||
|
$cfg['db_database'] = dirname(__FILE__).'/test.db';
|
||||||
|
# $cfg['idf_extra_upload_ext'] = 'ext1 ext2';
|
||||||
|
# $cfg['max_upload_size'] = 2097152;
|
||||||
|
# $cfg['time_zone'] = 'Europe/Berlin';
|
||||||
|
$cfg['pear_path'] = '/usr/share/php';
|
||||||
|
$cfg['login_success_url'] = $cfg['url_base'].$cfg['idf_base'];
|
||||||
|
$cfg['after_logout_page'] = $cfg['url_base'].$cfg['idf_base'];
|
||||||
|
$cfg['cache_engine'] = 'Pluf_Cache_File';
|
||||||
|
$cfg['cache_timeout'] = 300;
|
||||||
|
$cfg['cache_file_folder'] = $cfg['tmp_folder'].'/cache';
|
||||||
|
$cfg['template_folders'] = array(dirname(__FILE__).'/../src/IDF/templates');
|
||||||
|
$cfg['installed_apps'] = array('Pluf', 'IDF');
|
||||||
|
$cfg['pluf_use_rowpermission'] = true;
|
||||||
|
$cfg['middleware_classes'] = array(
|
||||||
|
'Pluf_Middleware_Csrf',
|
||||||
|
'Pluf_Middleware_Session',
|
||||||
|
'IDF_Middleware',
|
||||||
|
'Pluf_Middleware_Translation',
|
||||||
|
);
|
||||||
|
$cfg['template_context_processors'] = array('IDF_Middleware_ContextPreProcessor');
|
||||||
|
$cfg['idf_views'] = dirname(__FILE__).'/../src/IDF/conf/urls.php';
|
||||||
|
|
||||||
|
$cfg['languages'] = array('en', 'fr', 'de', 'es_ES');
|
||||||
|
$cfg['allowed_scm'] = array(
|
||||||
|
'git' => 'IDF_Scm_Git',
|
||||||
|
'svn' => 'IDF_Scm_Svn',
|
||||||
|
'mercurial' => 'IDF_Scm_Mercurial',
|
||||||
|
'mtn' => 'IDF_Scm_Monotone',
|
||||||
|
);
|
||||||
|
# $cfg['git_core_quotepath'] = false;
|
||||||
|
# $cfg['idf_strong_key_check'] = false;
|
||||||
|
# $cfg['idf_mimetypes_db'] = '/etc/mime.types';
|
||||||
|
# $cfg['idf_extra_text_ext'] = 'ext1 ext2 ext3';
|
||||||
|
# $cfg['idf_exec_cmd_prefix'] = '/usr/bin/env -i ';
|
||||||
|
# $cfg['svn_path'] = 'svn';
|
||||||
|
# $cfg['svnlook_path'] = 'svnlook';
|
||||||
|
# $cfg['svnadmin_path'] = 'svnadmin';
|
||||||
|
# $cfg['hg_path'] = 'hg';
|
||||||
|
# $cfg['git_path'] = 'git';
|
||||||
|
# $cfg['idf_no_size_check'] = false;
|
||||||
|
|
||||||
|
return $cfg;
|
||||||
|
|
1032
test/data/IDF_DiffTest/test-01-svn-new-files.diff
Normal file
1032
test/data/IDF_DiffTest/test-01-svn-new-files.diff
Normal file
File diff suppressed because it is too large
Load Diff
1
test/data/IDF_DiffTest/test-01-svn-new-files.expected
Normal file
1
test/data/IDF_DiffTest/test-01-svn-new-files.expected
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,389 @@
|
|||||||
|
Index: LinuxBIOSv1/src/include/cpu/i786/cpufixup.h
|
||||||
|
===================================================================
|
||||||
|
--- LinuxBIOSv1/src/include/cpu/i786/cpufixup.h (Revision 0)
|
||||||
|
+++ LinuxBIOSv1/src/include/cpu/i786/cpufixup.h (Revision 665)
|
||||||
|
@@ -0,0 +1,11 @@
|
||||||
|
+#ifndef CPU_I786_CPUFIXUP_H
|
||||||
|
+#define CPU_I786_CPUFIXUP_H
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+void i786_cpufixup(struct mem_range *mem);
|
||||||
|
+
|
||||||
|
+#define L3_CACHE_DISABLE 0x40
|
||||||
|
+
|
||||||
|
+#endif /* CPU_I786_CPUFIXUP_H */
|
||||||
|
+
|
||||||
|
+
|
||||||
|
|
||||||
|
Eigenschaftsänderungen: LinuxBIOSv1\src\include\cpu\i786\cpufixup.h
|
||||||
|
___________________________________________________________________
|
||||||
|
Hinzugefügt: svn:keywords
|
||||||
|
+ Author Date Id Revision
|
||||||
|
Hinzugefügt: svn:eol-style
|
||||||
|
+ native
|
||||||
|
|
||||||
|
Index: LinuxBIOSv1/src/mainboard/tyan/guiness/cmos.layout
|
||||||
|
===================================================================
|
||||||
|
--- LinuxBIOSv1/src/mainboard/tyan/guiness/cmos.layout (Revision 0)
|
||||||
|
+++ LinuxBIOSv1/src/mainboard/tyan/guiness/cmos.layout (Revision 665)
|
||||||
|
@@ -0,0 +1,63 @@
|
||||||
|
+entries
|
||||||
|
+
|
||||||
|
+#start-bit length config config-ID name
|
||||||
|
+#0 8 r 0 seconds
|
||||||
|
+#8 8 r 0 alarm_seconds
|
||||||
|
+#16 8 r 0 minutes
|
||||||
|
+#24 8 r 0 alarm_minutes
|
||||||
|
+#32 8 r 0 hours
|
||||||
|
+#40 8 r 0 alarm_hours
|
||||||
|
+#48 8 r 0 day_of_week
|
||||||
|
+#56 8 r 0 day_of_month
|
||||||
|
+#64 8 r 0 month
|
||||||
|
+#72 8 r 0 year
|
||||||
|
+#80 4 r 0 rate_select
|
||||||
|
+#84 3 r 0 REF_Clock
|
||||||
|
+#87 1 r 0 UIP
|
||||||
|
+#88 1 r 0 auto_switch_DST
|
||||||
|
+#89 1 r 0 24_hour_mode
|
||||||
|
+#90 1 r 0 binary_values_enable
|
||||||
|
+#91 1 r 0 square-wave_out_enable
|
||||||
|
+#92 1 r 0 update_finished_enable
|
||||||
|
+#93 1 r 0 alarm_interrupt_enable
|
||||||
|
+#94 1 r 0 periodic_interrupt_enable
|
||||||
|
+#95 1 r 0 disable_clock_updates
|
||||||
|
+#96 288 r 0 temporary_filler
|
||||||
|
+0 384 r 0 reserved_memory
|
||||||
|
+384 1 e 4 boot_option
|
||||||
|
+385 1 e 4 last_boot
|
||||||
|
+386 3 e 5 baud_rate
|
||||||
|
+392 4 e 6 debug_level
|
||||||
|
+396 1 e 1 power_on_after_fail
|
||||||
|
+#401 1 e 1 ECC_memory
|
||||||
|
+#402 1 e 2 hda_disk
|
||||||
|
+#403 1 e 2 hdb_disk
|
||||||
|
+#404 1 e 2 hdc_disk
|
||||||
|
+#405 1 e 2 hdd_disk
|
||||||
|
+#406 2 e 7 boot_device
|
||||||
|
+
|
||||||
|
+enumerations
|
||||||
|
+
|
||||||
|
+#ID value text
|
||||||
|
+1 0 Disable
|
||||||
|
+1 1 Enable
|
||||||
|
+#2 0 No
|
||||||
|
+#2 1 Yes
|
||||||
|
+4 0 Fallback
|
||||||
|
+4 1 Normal
|
||||||
|
+5 0 115200
|
||||||
|
+5 1 57600
|
||||||
|
+5 2 38400
|
||||||
|
+5 3 19200
|
||||||
|
+5 4 9600
|
||||||
|
+5 5 4800
|
||||||
|
+5 6 2400
|
||||||
|
+5 7 1200
|
||||||
|
+6 6 Notice
|
||||||
|
+6 7 Info
|
||||||
|
+6 8 Debug
|
||||||
|
+6 9 Spew
|
||||||
|
+#7 0 Network
|
||||||
|
+#7 1 HDD
|
||||||
|
+#7 2 Floppy
|
||||||
|
+#7 3 ROM
|
||||||
|
|
||||||
|
Eigenschaftsänderungen: LinuxBIOSv1\src\mainboard\tyan\guiness\cmos.layout
|
||||||
|
___________________________________________________________________
|
||||||
|
Hinzugefügt: svn:keywords
|
||||||
|
+ Author Date Id Revision
|
||||||
|
Hinzugefügt: svn:eol-style
|
||||||
|
+ native
|
||||||
|
|
||||||
|
Index: LinuxBIOSv1/src/config/linuxbios_c.ld
|
||||||
|
===================================================================
|
||||||
|
--- LinuxBIOSv1/src/config/linuxbios_c.ld (Revision 0)
|
||||||
|
+++ LinuxBIOSv1/src/config/linuxbios_c.ld (Revision 665)
|
||||||
|
@@ -0,0 +1,105 @@
|
||||||
|
+/*
|
||||||
|
+ * Memory map:
|
||||||
|
+ *
|
||||||
|
+ * _RAMBASE
|
||||||
|
+ * : data segment
|
||||||
|
+ * : bss segment
|
||||||
|
+ * : heap
|
||||||
|
+ * : stack
|
||||||
|
+ */
|
||||||
|
+/*
|
||||||
|
+ * Bootstrap code for the STPC Consumer
|
||||||
|
+ * Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
|
||||||
|
+ *
|
||||||
|
+ * $Id$
|
||||||
|
+ *
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Written by Johan Rydberg, based on work by Daniel Kahlin.
|
||||||
|
+ * Rewritten by Eric Biederman
|
||||||
|
+ */
|
||||||
|
+/*
|
||||||
|
+ * We use ELF as output format. So that we can
|
||||||
|
+ * debug the code in some form.
|
||||||
|
+ */
|
||||||
|
+INCLUDE ldoptions
|
||||||
|
+
|
||||||
|
+ENTRY(_start)
|
||||||
|
+
|
||||||
|
+SECTIONS
|
||||||
|
+{
|
||||||
|
+ . = _RAMBASE;
|
||||||
|
+ /*
|
||||||
|
+ * First we place the code and read only data (typically const declared).
|
||||||
|
+ * This get placed in rom.
|
||||||
|
+ */
|
||||||
|
+ .text : {
|
||||||
|
+ _text = .;
|
||||||
|
+ *(.text);
|
||||||
|
+ *(.text.*);
|
||||||
|
+ . = ALIGN(16);
|
||||||
|
+ _etext = .;
|
||||||
|
+ }
|
||||||
|
+ .rodata : {
|
||||||
|
+ _rodata = .;
|
||||||
|
+ . = ALIGN(4);
|
||||||
|
+ streams = . ;
|
||||||
|
+ *(.rodata.streams)
|
||||||
|
+ estreams = .;
|
||||||
|
+ . = ALIGN(4);
|
||||||
|
+ pci_drivers = . ;
|
||||||
|
+ *(.rodata.pci_drivers)
|
||||||
|
+ epci_drivers = . ;
|
||||||
|
+ *(.rodata)
|
||||||
|
+ *(.rodata.*)
|
||||||
|
+ _erodata = .;
|
||||||
|
+ }
|
||||||
|
+ /*
|
||||||
|
+ * After the code we place initialized data (typically initialized
|
||||||
|
+ * global variables). This gets copied into ram by startup code.
|
||||||
|
+ * __data_start and __data_end shows where in ram this should be placed,
|
||||||
|
+ * whereas __data_loadstart and __data_loadend shows where in rom to
|
||||||
|
+ * copy from.
|
||||||
|
+ */
|
||||||
|
+ .data : {
|
||||||
|
+ _data = .;
|
||||||
|
+ *(.data)
|
||||||
|
+ _edata = .;
|
||||||
|
+ }
|
||||||
|
+ /*
|
||||||
|
+ * bss does not contain data, it is just a space that should be zero
|
||||||
|
+ * initialized on startup. (typically uninitialized global variables)
|
||||||
|
+ * crt0.S fills between _bss and _ebss with zeroes.
|
||||||
|
+ */
|
||||||
|
+ _bss = .;
|
||||||
|
+ .bss . : {
|
||||||
|
+ *(.bss)
|
||||||
|
+ *(.sbss)
|
||||||
|
+ *(COMMON)
|
||||||
|
+ }
|
||||||
|
+ _ebss = .;
|
||||||
|
+ _end = .;
|
||||||
|
+ _stack = .;
|
||||||
|
+ .stack . : {
|
||||||
|
+ /* Reserve a stack for each possible cpu, +1 extra */
|
||||||
|
+ . = ((MAX_CPUS * STACK_SIZE) + STACK_SIZE) ;
|
||||||
|
+ }
|
||||||
|
+ _estack = .;
|
||||||
|
+ _heap = .;
|
||||||
|
+ .heap . : {
|
||||||
|
+ /* Reserve 256K for the heap */
|
||||||
|
+ . = HEAP_SIZE ;
|
||||||
|
+ . = ALIGN(4);
|
||||||
|
+ }
|
||||||
|
+ _eheap = .;
|
||||||
|
+ /* The ram segment
|
||||||
|
+ * This is all address of the memory resident copy of linuxBIOS.
|
||||||
|
+ */
|
||||||
|
+ _ram_seg = _text;
|
||||||
|
+ _eram_seg = _eheap;
|
||||||
|
+ /DISCARD/ : {
|
||||||
|
+ *(.comment)
|
||||||
|
+ *(.note)
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
|
||||||
|
Eigenschaftsänderungen: LinuxBIOSv1\src\config\linuxbios_c.ld
|
||||||
|
___________________________________________________________________
|
||||||
|
Hinzugefügt: svn:keywords
|
||||||
|
+ Author Date Id Revision
|
||||||
|
Hinzugefügt: svn:eol-style
|
||||||
|
+ native
|
||||||
|
|
||||||
|
Index: LinuxBIOSv1/src/arch/i386/include/arch/rom_segs.h
|
||||||
|
===================================================================
|
||||||
|
--- LinuxBIOSv1/src/arch/i386/include/arch/rom_segs.h (Revision 0)
|
||||||
|
+++ LinuxBIOSv1/src/arch/i386/include/arch/rom_segs.h (Revision 665)
|
||||||
|
@@ -0,0 +1,10 @@
|
||||||
|
+#ifndef ROM_SEGS_H
|
||||||
|
+#define ROM_SEGS_H
|
||||||
|
+
|
||||||
|
+#define ROM_CODE_SEG 0x08
|
||||||
|
+#define ROM_DATA_SEG 0x10
|
||||||
|
+
|
||||||
|
+#define CACHE_RAM_CODE_SEG 0x18
|
||||||
|
+#define CACHE_RAM_DATA_SEG 0x20
|
||||||
|
+
|
||||||
|
+#endif /* ROM_SEGS_H */
|
||||||
|
|
||||||
|
Eigenschaftsänderungen: LinuxBIOSv1\src\arch\i386\include\arch\rom_segs.h
|
||||||
|
___________________________________________________________________
|
||||||
|
Hinzugefügt: svn:keywords
|
||||||
|
+ Author Date Id Revision
|
||||||
|
Hinzugefügt: svn:eol-style
|
||||||
|
+ native
|
||||||
|
|
||||||
|
Index: LinuxBIOSv1/src/arch/i386/lib/c_start.S
|
||||||
|
===================================================================
|
||||||
|
--- LinuxBIOSv1/src/arch/i386/lib/c_start.S (Revision 0)
|
||||||
|
+++ LinuxBIOSv1/src/arch/i386/lib/c_start.S (Revision 665)
|
||||||
|
@@ -0,0 +1,135 @@
|
||||||
|
+#include <arch/asm.h>
|
||||||
|
+#include <arch/intel.h>
|
||||||
|
+#ifdef SMP
|
||||||
|
+#include <cpu/p6/apic.h>
|
||||||
|
+#endif
|
||||||
|
+ .section ".text"
|
||||||
|
+ .code32
|
||||||
|
+ .globl _start
|
||||||
|
+_start:
|
||||||
|
+ cli
|
||||||
|
+ lgdt %cs:gdtaddr
|
||||||
|
+ ljmp $0x10, $1f
|
||||||
|
+1: movl $0x18, %ax
|
||||||
|
+ movl %eax, %ds
|
||||||
|
+ movl %eax, %es
|
||||||
|
+ movl %eax, %ss
|
||||||
|
+ movl %eax, %fs
|
||||||
|
+ movl %eax, %gs
|
||||||
|
+
|
||||||
|
+ intel_chip_post_macro(0x13) /* post 12 */
|
||||||
|
+
|
||||||
|
+ /** clear stack */
|
||||||
|
+ leal EXT(_stack), %edi
|
||||||
|
+ movl $EXT(_estack), %ecx
|
||||||
|
+ subl %edi, %ecx
|
||||||
|
+ xorl %eax, %eax
|
||||||
|
+ rep
|
||||||
|
+ stosb
|
||||||
|
+
|
||||||
|
+ /** clear bss */
|
||||||
|
+ leal EXT(_bss), %edi
|
||||||
|
+ movl $EXT(_ebss), %ecx
|
||||||
|
+ subl %edi, %ecx
|
||||||
|
+ jz .Lnobss
|
||||||
|
+ xorl %eax, %eax
|
||||||
|
+ rep
|
||||||
|
+ stosb
|
||||||
|
+.Lnobss:
|
||||||
|
+
|
||||||
|
+ /* set new stack */
|
||||||
|
+ movl $_estack, %esp
|
||||||
|
+#ifdef SMP
|
||||||
|
+ /* Get the cpu id */
|
||||||
|
+ movl $APIC_DEFAULT_BASE, %edi
|
||||||
|
+ movl APIC_ID(%edi), %eax
|
||||||
|
+ shrl $24, %eax
|
||||||
|
+
|
||||||
|
+ /* Get the cpu index (MAX_CPUS on error) */
|
||||||
|
+ movl $-4, %ebx
|
||||||
|
+1: addl $4, %ebx
|
||||||
|
+ cmpl $(MAX_CPUS << 2), %ebx
|
||||||
|
+ je 2
|
||||||
|
+ cmpl %eax, EXT(initial_apicid)(%ebx)
|
||||||
|
+ jne 1b
|
||||||
|
+2: shrl $2, %ebx
|
||||||
|
+
|
||||||
|
+ /* Now compute the appropriate stack */
|
||||||
|
+ movl %ebx, %eax
|
||||||
|
+ movl $STACK_SIZE, %ebx
|
||||||
|
+ mull %ebx
|
||||||
|
+ subl %eax, %esp
|
||||||
|
+
|
||||||
|
+ /* push the boot_complete flag */
|
||||||
|
+ pushl %ebp
|
||||||
|
+
|
||||||
|
+ /* Save the stack location */
|
||||||
|
+ movl %esp, %ebp
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Now we are finished. Memory is up, data is copied and
|
||||||
|
+ * bss is cleared. Now we call the main routine and
|
||||||
|
+ * let it do the rest.
|
||||||
|
+ */
|
||||||
|
+ intel_chip_post_macro(0xfe) /* post fe */
|
||||||
|
+
|
||||||
|
+ /* Resort the stack location */
|
||||||
|
+ movl %ebp, %esp
|
||||||
|
+
|
||||||
|
+ /* The boot_complete flag has already been pushed */
|
||||||
|
+ call EXT(hardwaremain)
|
||||||
|
+ /*NOTREACHED*/
|
||||||
|
+.Lhlt:
|
||||||
|
+ intel_chip_post_macro(0xee) /* post fe */
|
||||||
|
+ hlt
|
||||||
|
+ jmp .Lhlt
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ .globl gdt, gdt_end, gdt_limit
|
||||||
|
+
|
||||||
|
+gdt_limit = gdt_end - gdt - 1 /* compute the table limit */
|
||||||
|
+gdtaddr:
|
||||||
|
+ .word gdt_limit
|
||||||
|
+ .long gdt /* we know the offset */
|
||||||
|
+
|
||||||
|
+gdt:
|
||||||
|
+// selgdt 0
|
||||||
|
+ .word 0x0000, 0x0000 /* dummy */
|
||||||
|
+ .byte 0x00, 0x00, 0x00, 0x00
|
||||||
|
+
|
||||||
|
+// selgdt 8
|
||||||
|
+ .word 0x0000, 0x0000 /* dummy */
|
||||||
|
+ .byte 0x00, 0x00, 0x00, 0x00
|
||||||
|
+
|
||||||
|
+// selgdt 0x10
|
||||||
|
+/* flat code segment */
|
||||||
|
+ .word 0xffff, 0x0000
|
||||||
|
+ .byte 0x00, 0x9b, 0xcf, 0x00
|
||||||
|
+
|
||||||
|
+//selgdt 0x18
|
||||||
|
+/* flat data segment */
|
||||||
|
+ .word 0xffff, 0x0000
|
||||||
|
+ .byte 0x00, 0x93, 0xcf, 0x00
|
||||||
|
+
|
||||||
|
+//selgdt 0x20
|
||||||
|
+ .word 0x0000, 0x0000 /* dummy */
|
||||||
|
+ .byte 0x00, 0x00, 0x00, 0x00
|
||||||
|
+
|
||||||
|
+#if defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
|
||||||
|
+ // from monty:
|
||||||
|
+ /* 0x00009a00,0000ffffULL, 20h: 16-bit 64k code at 0x00000000 */
|
||||||
|
+ /* 0x00009200,0000ffffULL 28h: 16-bit 64k data at 0x00000000 */
|
||||||
|
+// selgdt 0x28
|
||||||
|
+/*16-bit 64k code at 0x00000000 */
|
||||||
|
+ .word 0xffff, 0x0000
|
||||||
|
+ .byte 0, 0x9a, 0, 0
|
||||||
|
+
|
||||||
|
+// selgdt 0x30
|
||||||
|
+/*16-bit 64k data at 0x00000000 */
|
||||||
|
+ .word 0xffff, 0x0000
|
||||||
|
+ .byte 0, 0x92, 0, 0
|
||||||
|
+#endif // defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
|
||||||
|
+gdt_end:
|
||||||
|
+
|
||||||
|
+.code32
|
||||||
|
|
||||||
|
Eigenschaftsänderungen: LinuxBIOSv1\src\arch\i386\lib\c_start.S
|
||||||
|
___________________________________________________________________
|
||||||
|
Hinzugefügt: svn:keywords
|
||||||
|
+ Author Date Id Revision
|
||||||
|
Hinzugefügt: svn:eol-style
|
||||||
|
+ native
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user