Compare commits

...
59 Commits
Author SHA1 Message Date
pvincent 9b94726d39 tagged as 1.16.0 2023-03-28 11:56:15 +04:00
pvincent 2704620b90 mentions legales from config 2023-03-28 11:56:06 +04:00
pvincent 784438c864 tagged as 1.15.1 2022-12-11 12:18:34 +04:00
pvincent 6494f92b54 meilleur consentement cookies 2022-12-11 12:18:23 +04:00
pvincent a7e75fb40b tagged as 1.15.0 2022-12-10 19:48:39 +04:00
pvincent 1b6fc0e646 tout accepter 2022-12-10 19:48:04 +04:00
pvincent 01612db559 tagged as 1.14.3 2022-12-10 19:36:44 +04:00
pvincent a0405e885d cookie consent OK 2022-12-10 19:36:21 +04:00
pvincent fc5e1cc4d2 tagged as 1.14.2 2022-12-10 12:55:47 +04:00
pvincent 5db8f5f1f3 mentions légales 2022-12-10 12:55:23 +04:00
pvincent 0c45dffc1e tagged as 1.14.1 2022-11-29 10:52:35 +04:00
pvincent 5bc2ad1517 view misses div class row 2022-11-29 10:52:17 +04:00
pvincent a6eed18ac1 tagged as 1.14.0 2022-11-29 10:29:24 +04:00
pvincent 67bbb02a2f footer reuse 2022-11-29 10:29:03 +04:00
pvincent 8fe3153c10 tagged as 1.13.6 2022-11-25 09:55:46 +04:00
pvincent de0f10425b Main redirect if group 1 exists 2022-11-25 09:55:38 +04:00
pvincent 4bd7c3d174 tagged as 1.13.5 2022-11-23 11:05:10 +04:00
pvincent ad1ae04624 logo france relance 2022-11-23 11:04:54 +04:00
pvincent dad6babe97 tagged as 1.13.4 2022-11-22 12:00:13 +04:00
pvincent 240c63d9fd wiki update 2022-11-22 12:00:02 +04:00
pvincent d6675758ff tagged as 1.13.3 2022-11-21 22:54:40 +04:00
pvincent 61ce852dbc package json fixed 2022-11-21 22:54:30 +04:00
pvincent 789a4eb7ec tagged as 1.13.2 2022-11-21 22:32:06 +04:00
pvincent 2b0f3557fc no more www/file in git 2022-11-21 22:31:58 +04:00
pvincent 10688b9892 tagged as 1.13.1 2022-11-21 22:22:36 +04:00
pvincent c86eafa130 ok 2022-11-21 22:22:27 +04:00
pvincent b2b7e88e3c by default /group/1 2022-11-21 22:21:56 +04:00
pvincent c078d7cf16 tagged as 1.12.0 2022-11-16 09:11:06 +04:00
pvincent f2c6c05a00 bandeau_region via config.xml 2022-11-16 09:09:36 +04:00
pvincent c163807c96 tagged as 1.11.9 2022-08-24 10:04:36 +04:00
pvincent 5cbc81a07a file/.htaccess required 2022-08-24 10:04:25 +04:00
pvincent 22a78d1fef tagged as 1.11.8 2022-08-23 22:05:07 +04:00
pvincent 6eb02e94ce makefile 2022-08-23 22:04:57 +04:00
pvincent 5116f6b60d tagged as 1.11.7 2022-08-23 21:56:32 +04:00
pvincent 9edfa4f40e package.json 2022-08-23 21:54:01 +04:00
pvincent 4b9fd45d92 tagged as 1.11.6 2022-08-23 21:49:31 +04:00
pvincent 42b07fea6a lang owend by www-data 2022-08-23 21:49:19 +04:00
pvincent 04a526e728 tagged as 1.11.5 2022-08-22 10:59:40 +04:00
pvincent e28efeab7e re-enable config.xml 2022-08-22 10:59:30 +04:00
pvincent bc939a5bdb tagged as 1.11.4 2022-08-22 10:48:54 +04:00
pvincent 4a052ea707 no more config.xml first time 2022-08-22 10:48:41 +04:00
pvincent f139fcfefb Update 'README.md' 2021-12-03 20:18:54 +04:00
pvincent 347a81dc66 Update 'README.md' 2021-08-31 21:34:26 +04:00
pvincent d142fc1eac Update 'README.md' 2021-08-31 21:22:59 +04:00
pvincent e039ed4fe5 better readme 2021-08-31 20:04:52 +04:00
pvincent 44d2248ba5 screenshot 2021-08-31 19:54:35 +04:00
pvincent 34e7527442 screenshot 2021-08-31 19:15:28 +04:00
pvincent ecffe9bb4e tagged as 1.11.3 2021-08-30 23:22:46 +04:00
pvincent 6e7382633f css footer margin 0 2021-08-30 23:22:19 +04:00
pvincent bb50c92230 tagged as 1.11.2 2021-08-30 22:49:49 +04:00
pvincent 98dffaebed fix config missing key 2021-08-30 22:49:34 +04:00
pvincent ca6aceffbc tagged as 1.11.1 2021-08-30 21:48:13 +04:00
pvincent c4ea83cca9 better README 2021-08-30 21:47:25 +04:00
pvincent 6c4aa6d9ea tagged as 1.11.0 2021-08-30 21:10:58 +04:00
pvincent cdfe52715f simpler config + new logo 2021-08-30 21:10:33 +04:00
pvincent 8bd119a818 maintain 2021-08-30 18:30:00 +04:00
pvincent 0854d556fe cagettepéi 2021-08-30 17:44:14 +04:00
pvincent 278f69e7d9 tagged as 1.10.2 2021-08-29 21:31:33 +04:00
pvincent 8699728593 version cagettepei 2021-08-29 21:31:16 +04:00
38 changed files with 2145 additions and 2129 deletions
+2 -2
View File
@@ -25,11 +25,11 @@ lang/es/tmp/*.n
www/lang/*.mo
www/file/*
www/js/app.js
www/js/libs.js
www/file/*
www/css/.sass-cache
www/css/*.css
!www/css/bootstrap.min.css
+1 -1
View File
@@ -1 +1 @@
1.10.1
1.16.0
+2 -1
View File
@@ -73,8 +73,9 @@ templates:
haxe cagette.hxml -D i18n_generation
@make LANG=fr ctemplates
msgfmt www/lang/texts_fr.po -o www/lang/texts_fr.mo
chown www-data:www-data -R www
chown www-data:www-data -R lang/fr
chown www-data:www-data -R lang
ctemplates:
(cd lang/$(LANG)/tpl; temploc2 -macros macros.mtt -output ../tmp/ *.mtt */*.mtt */*/*.mtt)
+66 -50
View File
@@ -1,69 +1,82 @@
CAGETTE PEI
===========
Fourche du logiciel [Cagette.net](https://github.com/CagetteNet) à partir de la version 0.9.2 Novembre 2018
Cagette Péi est un logiciel libre qui favorise les circuits courts.
Il a été adapté pour les besoins des AMAPs sur le marché réunionnais.
Certaines portions du code source de Cagette.net n'étant plus disponibles en téléchargement,
j'ai repris sur la base d'un existant pour adapter au marché local réunionnais et leurs AMAPéi.
> <french>
> Fourche du logiciel [Cagette.net](https://github.com/CagetteNet) à partir de la version 0.9.2 Novembre 2018. Certaines portions de code n'étant plus disponibles en téléchargement à partir de cette date, le logiciel a été repris, adapté puis réactualisé. Pour plus d'information, contact@artcode.re
> </french>
## INSTALL FROM SCRATCH (debian-buster)
![Screenshot](www/img/screenshot.png)
* apt install -y curl
* curl -L https://deb.nodesource.com/setup_8.x | bash -
* apt install -y nodejs=8.17.0-1nodesource1
* apt install -y sudo haxe apache2 make git imagemagick gettext libapache2-mod-neko mariadb-server
* mysql -u root <<EOF
## PREREQUISITE MARIADB
```bash
apt install -y mariadb-server
mysql -u root <<EOF
CREATE DATABASE cagettepei;
GRANT ALL ON cagettepei.* TO 'cagettepei'@'%' IDENTIFIED BY 'cagettepei';
EOF
* cd /var/www
* git clone https://git.artcode.re/cagetters/cagettepei.git
* cd cagettepei
* make install ENV=dev # first time
* make compile # classes
* make templates # templates + i18n
* vim /etc/apache2/sites-available/cagettepei.conf
```
## INSTALL FROM SCRATCH
Rk: Works on any Debian (>=Buster) compatible server!
```
apt install -y curl
curl -L https://deb.nodesource.com/setup_8.x | bash -
apt install -y nodejs=8.17.0-1nodesource1
apt install -y sudo haxe apache2 make git imagemagick gettext libapache2-mod-neko mariadb-server sendemail libio-socket-ssl-perl libnet-ssleay-perl
cd /var/www
git clone https://git.artcode.re/cagetters/cagettepei.git
cd cagettepei
make install ENV=dev
vim /etc/apache2/sites-available/cagettepei.conf
```
```
<VirtualHost *:80>
ServerName cagettepei
DirectoryIndex index.n
DocumentRoot /var/www/cagettepei/www/
DocumentRoot /var/www/cagettepei/www
DirectoryIndex index.n
CustomLog ${APACHE_LOG_DIR}/cagettepei/access.log combined
</VirtualHost>
```
* sed -i '/<Directory \/var\/www\/>/,/<\/Directory>/ s/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf
* a2dissite 000-default.conf
* a2ensite cagettepei.conf
* a2enmod neko rewrite
* systemctl restart apache2
```bash
sed -i '/<Directory \/var\/www\/>/,/<\/Directory>/ s/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf
a2dissite 000-default.conf
a2ensite cagettepei.conf
a2enmod rewrite
mkdir -p /var/log/apache2/cagettepei
systemctl restart apache2
```
## CONFIGURATION
* cd /var/www/cagettepei
* vim config.xml
```bash
cd /var/www/cagettepei
vim config.xml
```
```
<config
host="<DOMAIN.TLD>"
key="<SECRET_PHRASE>"
name = "CagettePéi"
host = "<DOMAIN.TLD>"
database = "mysql://cagettepei:cagettepei@localhost/cagettepei"
key = "<SECRET_PHRASE>"
default_email = "<EMAIL>"
webmaster_email = "<EMAIL>"
database="mysql://cagettepei:cagettepei@localhost/cagettepei"
smtp_host="localhost"
smtp_port="25"
smtp_user=""
smtp_pass=""
debug = "0"
sqllog = "0"
maintain = "0"
lang="fr"
langs="fr"
langnames="Français"
maintain="0"
debug="0"
sqllog="0"
cache="1"
cachetpl="0"
cache = "1"
cachetpl = "0"
/>
```
@@ -72,16 +85,19 @@ ADMIN RESET PASSWORD
go to http://localhost for ERROR + table regeneration, then
* cd /var/www/cagettepei
* SECRET=$(grep key= config.xml | cut -d= -f2 | cut -d'"' -f2)
* echo "insert into User values (1,'fr',MD5('${SECRET}cagettepei'),1,'Administrateur','Cagette Péi', 'admin', null, null, null, null, null, null, null, null, null, now(), now(),6,null, null)" | mysql -h localhost -u cagettepei -pcagettepei cagettepei
```
cd /var/www/cagettepei
SECRET=$(grep key config.xml | cut -d= -f2 | cut -d'"' -f2)
echo "insert into User values (1,'fr',MD5('${SECRET}cagettepei'),1,'Administrateur','Cagette Péi', 'admin', null, null, null, null, null, null, null, null, null, now(), now(),6,null, null)" | mysql -h localhost -u cagettepei -pcagettepei cagettepei
```
then, connect with admin / cagettepei
### change admin password
* echo "update User set pass=MD5('${SECRET}cagettepei') where id=1" | mysql -h localhost -u cagettepei -pcagettepei cagettepei
```
echo "update User set pass=MD5('${SECRET}cagettepei') where id=1" | mysql -h localhost -u cagettepei -pcagettepei cagettepei
```
SYSTEMD-TIMERS
--------------
@@ -98,7 +114,7 @@ SYSTEMD-TIMERS
SELECTOR=$1
for i in /var/www/cagettepei-* ; do
for i in /var/www/cagettepei* ; do
if [[ -d $i ]]; then
cd $i/www
echo "cron-$SELECTOR in: $i"
+13 -8
View File
@@ -1,19 +1,24 @@
<config
database = "mysql://<USER>:<PASSWORD>@<HOST>/<DBNAME>"
host = "<URL without http>"
name = "<HTML head title>"
default_email = "<EMAIL>"
webmaster_email = "<EMAIL>"
key = "<SECRET_PHRASE>"
maintain="0"
cache="1"
cachetpl="0"
debug="0"
sqllog="0"
maintain="0"
cache="1"
cachetpl="0"
legal.name="TODO"
legal.email="TODO"
legal.siren="TODO"
legal.siret="TODO"
legal.naf="TODO"
legal.juridique="TODO"
legal.responsable="TODO"
legal.hebergeur="<a href='mailto:TODO'>TODO</a>"
lang="fr"
langs="fr"
langnames="Français"
/>
+89 -85
View File
@@ -1,33 +1,33 @@
//React lib
// React lib
import react.ReactMacro.jsx;
import react.ReactDOM;
import react.*;
import react.router.*;
//custom components
// custom components
import react.order.*;
import react.product.*;
import react.store.*;
import react.map.*;
import react.user.*;
//require bootstrap JS since it's bundled with browserify
//@:jsRequire('bootstrap') extern class Bootstrap{}
//@:jsRequire('jquery') extern class JQ extends js.jquery.JQuery{}
// require bootstrap JS since it's bundled with browserify
// @:jsRequire('bootstrap') extern class Bootstrap{}
// @:jsRequire('jquery') extern class JQ extends js.jquery.JQuery{}
class App {
public static var instance:App;
public static var instance : App;
public var LANG : String;
public var currency : String; //currency symbol like &euro; or $
public var t : sugoi.i18n.GetText;//gettext translator
public var LANG:String;
public var currency:String; // currency symbol like &euro; or $
public var t:sugoi.i18n.GetText; // gettext translator
//i dont want to use redux now... saved state from react.OrderBox
public static var SAVED_ORDER_STATE : Dynamic;
// i dont want to use redux now... saved state from react.OrderBox
public static var SAVED_ORDER_STATE:Dynamic;
function new(?lang="fr",?currency="&euro;") {
//singleton
function new(?lang = "fr", ?currency = "&euro;") {
// singleton
instance = this;
if(lang!=null) this.LANG = lang;
if (lang != null)
this.LANG = lang;
this.currency = currency;
}
@@ -39,7 +39,7 @@ class App {
return new js.JQuery(r);
}
public static inline function jq(r:Dynamic):js.jquery.JQuery{
public static inline function jq(r:Dynamic):js.jquery.JQuery {
return new js.jquery.JQuery(r);
}
@@ -47,8 +47,7 @@ class App {
* The JS App will be available as "_" in the document.
*/
public static function main() {
//untyped js.Browser.window.$ = js.Lib.require("jQuery");
// untyped js.Browser.window.$ = js.Lib.require("jQuery");
untyped js.Browser.window._ = new App();
}
@@ -56,32 +55,31 @@ class App {
return new ShopCart();
}
public function getTagger(cid:Int ) {
public function getTagger(cid:Int) {
return new Tagger(cid);
}
public function getTuto(name:String, step:Int) {
new Tuto(name,step);
new Tuto(name, step);
}
/**
* remove method for IE compat
*/
public function remove(el:js.html.Element){
if (el == null) return;
public function remove(el:js.html.Element) {
if (el == null)
return;
el.parentElement.removeChild(el);
}
public function getVATBox(ttcprice:Float,currency:String,rates:String,vat:Float,formName:String){
public function getVATBox(ttcprice:Float, currency:String, rates:String, vat:Float, formName:String) {
var input = js.Browser.document.querySelector('form input[name="${formName}_price"]');
remove( js.Browser.document.querySelector('form input[name="${formName}_vat"]').parentElement.parentElement );
remove(js.Browser.document.querySelector('form input[name="${formName}_vat"]').parentElement.parentElement);
ReactDOM.render(jsx('<$VATBox ttc="$ttcprice" currency="$currency" vatRates="$rates" vat="$vat" formName="$formName"/>'), input.parentElement);
//remove(input);
// remove(input);
}
/*public function getProductComposer(){
@@ -89,7 +87,6 @@ class App {
//ReactDOM.render(jsx('<$ComposerApp/>'), js.Browser.document.getElementById("app"));
//});
}*/
/**
* Removes the form element and replace it by a react js component
* @param divId
@@ -97,72 +94,71 @@ class App {
* @param txpProductId
* @param formName
*/
public function getProductInput(divId:String, productName:String, txpProductId:String, formName:String ){
public function getProductInput(divId:String, productName:String, txpProductId:String, formName:String) {
js.Browser.document.addEventListener("DOMContentLoaded", function(event) {
// dirty stuff to remove "real" input, and replace it by the react one
App.j("form input[name='" + formName + "_name']").parent().parent().remove();
App.j("form select[name='" + formName + "_txpProductId']")
.parent()
.parent()
.remove();
//dirty stuff to remove "real" input, and replace it by the react one
App.j("form input[name='"+formName+"_name']").parent().parent().remove();
App.j("form select[name='" + formName+"_txpProductId']").parent().parent().remove();
if (txpProductId == null)
txpProductId = "";
if (txpProductId == null) txpProductId = "";
ReactDOM.render(jsx('<$ProductInput productName="$productName" txpProductId="$txpProductId" formName="$formName"/>'), js.Browser.document.getElementById(divId));
ReactDOM.render(jsx('<$ProductInput productName="$productName" txpProductId="$txpProductId" formName="$formName"/>'),
js.Browser.document.getElementById(divId));
});
}
public function initReportHeader(){
public function initReportHeader() {
ReactDOM.render(jsx('<$ReportHeader />'), js.Browser.document.querySelector('div.reportHeaderContainer'));
}
public function initOrderBox(userId:Int, distributionId:Int, contractId:Int, contractType:Int, date:String, place:String, userName:String, currency:String, hasPayments:Bool,callbackUrl:String){
public function initOrderBox(userId:Int, distributionId:Int, contractId:Int, contractType:Int, date:String, place:String, userName:String,
currency:String, hasPayments:Bool, callbackUrl:String) {
untyped App.j("#myModal").modal();
var onValidate = function() js.Browser.location.href = callbackUrl;
var node = js.Browser.document.querySelector('#myModal .modal-body');
ReactDOM.unmountComponentAtNode(node); //the previous modal DOM element is still there, so we need to destroy it
ReactDOM.unmountComponentAtNode(node); // the previous modal DOM element is still there, so we need to destroy it
ReactDOM.render(jsx('<$OrderBox userId="$userId" distributionId="$distributionId"
contractId="$contractId" contractType="$contractType" date="$date" place="$place" userName="$userName"
onValidate=$onValidate currency=$currency hasPayments=$hasPayments />'),node,postReact);
onValidate=$onValidate currency=$currency hasPayments=$hasPayments />'), node, postReact);
}
function postReact(){
function postReact() {
trace("post react");
haxe.Timer.delay(function(){
haxe.Timer.delay(function() {
untyped jq('[data-toggle="tooltip"]').tooltip();
untyped jq('[data-toggle="popover"]').popover();
},500);
}, 500);
}
public static function roundTo(n:Float, r:Int):Float {
return Math.round(n * Math.pow(10,r)) / Math.pow(10,r) ;
return Math.round(n * Math.pow(10, r)) / Math.pow(10, r);
}
/**
* Ajax loads a page and display it in a modal window
* @param url
* @param title
*/
public function overlay(url:String,?title,?large=true) {
if (title != null) title = StringTools.urlDecode(title);
public function overlay(url:String, ?title, ?large = true) {
if (title != null)
title = StringTools.urlDecode(title);
var r = new haxe.Http(url);
r.onData = function(data) {
//setup body and title
// setup body and title
var m = App.j("#myModal");
m.find(".modal-body").html(data);
if (title != null) m.find(".modal-title").html(title);
if (title != null)
m.find(".modal-title").html(title);
if (!large) m.find(".modal-dialog").removeClass("modal-lg");
untyped App.j('#myModal').modal(); //bootstrap 3 modal window
if (!large)
m.find(".modal-dialog").removeClass("modal-lg");
untyped App.j('#myModal').modal(); // bootstrap 3 modal window
}
r.request();
}
@@ -170,24 +166,37 @@ class App {
/**
* Displays a login box
*/
public function loginBox(redirectUrl:String,?message:String,?phoneRequired=false) {
public function loginBox(redirectUrl:String, ?message:String, ?phoneRequired = false) {
var m = App.j("#myModal");
m.find(".modal-title").html("S'identifier");
m.find(".modal-dialog").removeClass("modal-lg");
untyped m.modal();
ReactDOM.render(jsx('<$LoginBox redirectUrl="$redirectUrl" message=$message phoneRequired="$phoneRequired"/>'), js.Browser.document.querySelector('#myModal .modal-body'));
ReactDOM.render(jsx('<$LoginBox redirectUrl="$redirectUrl" message=$message phoneRequired="$phoneRequired"/>'),
js.Browser.document.querySelector('#myModal .modal-body'));
return false;
}
/**
* Displays a sign up box
*/
public function registerBox(redirectUrl:String,?message:String,?phoneRequired=false) {
public function registerBox(redirectUrl:String, ?message:String, ?phoneRequired = false) {
var m = App.j("#myModal");
m.find(".modal-title").html("S'inscrire");
m.find(".modal-dialog").removeClass("modal-lg");
untyped m.modal();
ReactDOM.render(jsx('<$RegisterBox redirectUrl="$redirectUrl" message=$message phoneRequired="$phoneRequired"/>'), js.Browser.document.querySelector('#myModal .modal-body'));
ReactDOM.render(jsx('<$RegisterBox redirectUrl="$redirectUrl" message=$message phoneRequired="$phoneRequired"/>'),
js.Browser.document.querySelector('#myModal .modal-body'));
return false;
}
public function cookieConsentBox(redirectUrl:String, ?message:String, ?phoneRequired = false) {
js.Browser.console.log("cookieConsentBox should load modal...");
var m = App.j("#myModal");
m.find(".modal-title").html("Consentement aux cookies");
m.find(".modal-dialog").removeClass("modal-lg");
untyped m.modal();
ReactDOM.render(jsx('<$CookieConsentBox redirectUrl="$redirectUrl" message=$message phoneRequired="$phoneRequired"/>'),
js.Browser.document.querySelector('#myModal .modal-body'));
return false;
}
@@ -195,7 +204,7 @@ class App {
ReactDOM.render(jsx('<$Store date=$date place=$place/>'), js.Browser.document.querySelector('#shop'));
}
public function groupMap(lat:String,lng:String,address:String) {
public function groupMap(lat:String, lng:String, address:String) {
ReactDOM.render(jsx('<$GroupMapRoot lat="$lat" lng="$lng" address="$address"/>'), js.Browser.document.querySelector('#map'));
}
@@ -203,19 +212,19 @@ class App {
* Helper to get values of a bunch of checked checkboxes
* @param formSelector
*/
public function getCheckboxesId(formSelector:String):Array<String>{
public function getCheckboxesId(formSelector:String):Array<String> {
var out = [];
var checkboxes = js.Browser.document.querySelectorAll(formSelector + " input[type=checkbox]");
for ( input in checkboxes ){
var input : js.html.InputElement = cast input;
if ( input.checked ) out.push(input.value);
for (input in checkboxes) {
var input:js.html.InputElement = cast input;
if (input.checked)
out.push(input.value);
}
return out;
}
#if plugins
public function getHostedPlugin(){
public function getHostedPlugin() {
return new hosted.js.App();
}
#end
@@ -223,40 +232,35 @@ class App {
/**
* set up a warning message when leaving the page
*/
public function setWarningOnUnload(active:Bool, ?msg:String){
if (active){
public function setWarningOnUnload(active:Bool, ?msg:String) {
if (active) {
js.Browser.window.addEventListener("beforeunload", warn);
}else{
} else {
js.Browser.window.removeEventListener("beforeunload", warn);
}
}
function warn(e:js.html.Event) {
var msg = "Voulez vous vraiment quitter cette page ?";
//js.Browser.window.confirm(msg);
untyped e.returnValue = msg; //Gecko + IE
// js.Browser.window.confirm(msg);
untyped e.returnValue = msg; // Gecko + IE
e.preventDefault();
return msg; //Gecko + Webkit, Safari, Chrome etc.
return msg; // Gecko + Webkit, Safari, Chrome etc.
}
/**
* Anti Doubleclick with btn elements.
* Can be bypassed by adding a .btn-noAntiDoubleClick class
*/
public function antiDoubleClick(){
for( n in js.Browser.document.querySelectorAll(".btn:not(.btn-noAntiDoubleClick)") ){
n.addEventListener("click",function(e:js.html.MouseEvent){
public function antiDoubleClick() {
for (n in js.Browser.document.querySelectorAll(".btn:not(.btn-noAntiDoubleClick)")) {
n.addEventListener("click", function(e:js.html.MouseEvent) {
var x = untyped e.target;
x.classList.add("disabled");
haxe.Timer.delay(function(){
haxe.Timer.delay(function() {
x.classList.remove("disabled");
},1000);
}, 1000);
});
}
}
}
+103
View File
@@ -0,0 +1,103 @@
package react.user;
import react.ReactComponent;
import react.ReactMacro.jsx;
import Common;
typedef CookieConsentBoxProps = {
redirectUrl:String,
message:String,
?phoneRequired:Bool
}
typedef CookieConsentBoxState = {
email:String,
password:String,
error:String
}
/**
* CookieConsent Box
* @author fbarbut
*/
class CookieConsentBox extends react.ReactComponentOfPropsAndState<CookieConsentBoxProps, CookieConsentBoxState> {
public function new(props:CookieConsentBoxProps) {
if (props.redirectUrl == null || props.redirectUrl == "null")
props.redirectUrl = "/";
if (props.message == "")
props.message = null;
super(props);
this.state = {email: "", password: "", error: null};
}
function setError(err:String) {
this.setState(cast {error: err});
}
override public function render() {
return jsx('<div onKeyPress=$onKeyPress>
<$Error error="${state.error}" />
<$Message message="${props.message}" />
<form action="" method="post" className="form-horizontal">
<h4>Personnalisation du paramétrage</h4>
<p>L\'outil CagettePéi n\'utilise que des cookies nécessaires pour vous aider à naviguer efficacement et à exécuter certaines fonctionnalités. Pas de cookie publicitaire, en provenance de site tiers ou de mesure d\'audience.
</p>
<p>
Seuls les cookies nécessaires sont cruciaux pour les fonctions de base du site Web et celui-ci ne fonctionnera pas comme prévu sans eux. Ces cookies ne stockent aucune donnée personnellement identifiable.
</p>
<p className="text-center">
<a onClick={deny} className="btn btn-secondary btn-lg" ><span className="glyphicon glyphicon-remove"></span> Tout Refuser</a>
&nbsp;
<a onClick={submit} className="btn btn-primary btn-lg" ><span className="glyphicon glyphicon-ok"></span> Tout Accepter</a>
</p>
</form>
</div>');
}
/**
* @doc https://facebook.github.io/react/docs/forms.html
*/
function onChange(e:js.html.Event) {
e.preventDefault();
var name:String = untyped e.target.name;
var value:String = untyped /*(e.target.value == "") ? null :*/ e.target.value;
Reflect.setField(state, name, value);
this.setState(this.state);
}
public function submit(?e:js.html.Event) {
// lock button
var el:js.html.Element = null;
if (e != null) {
el = cast e.target;
el.classList.add("disabled");
}
// var cookie = js.Browser.document.cookie;
var newCookie = "rgpd=true; SameSite=Lax";
js.Browser.document.cookie = newCookie;
// js.Browser.window.location.href = props.redirectUrl;
js.Browser.window.location.href = '/';
}
public function deny(?e:js.html.Event) {
// lock button
var el:js.html.Element = null;
if (e != null) {
el = cast e.target;
el.classList.add("disabled");
}
var newCookie = "rgpd=false; SameSite=Lax";
js.Browser.document.cookie = newCookie;
// js.Browser.window.location.href = props.redirectUrl;
js.Browser.window.location.href = '/';
}
function onKeyPress(e:js.html.KeyboardEvent) {
if (e.key == "Enter")
submit();
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
::use 'admin/design.mtt'::
<h3>Console d'administration de Cagette.net</h3>
<h3>Console d'administration de CagettePéi</h3>
<p>
::hDate(now)::
</p>
+2 -139
View File
@@ -13,11 +13,7 @@
::if groupName!=null && noGroup!=true::
<h1>::groupName::</h1>
::else::
<div style="margin-bottom:22px;" >
<a href="https://git.artcode.re/cagetters/cagettepei" target="_blank">
<img src="/img/logo3.png" alt="::NAME::" />
</a>
</div>
<h1>::_("Cagette.net")::</h1>
::end::
</div>
@@ -127,141 +123,8 @@
</div>
</div>-->
<div class="row" id="footer">
<div class="col-md-9" >
<a href="https://git.artcode.re/cagetters/cagette" target="_blank">
<img src="/img/logo.png" alt="::_("Cagette.net")::"/>
</a>
</div>
<div class="col-md-3" >
::_("HELP")::
<ul>
<li>
<a href="http://www.cagette.net/wiki" target="_blank">::_("Documentation")::</a>
</li>
<li>
<a href="https://pad1.zourit.net/p/4a3b09afd25b4fdcb3f0a9598db21e61" target="_blank">Proposer une amélioration</a>
</li>
<li>
<a href="https://pad1.zourit.net/p/4a3b09afd25b4fdcb3f0a9598db21e61" target="_blank">Soumettre une anomalie</a>
</li>
</ul>
<!--<p style="position: absolute;display: block;top: 96px;width: 700px;">
<b>::raw _("Vous êtes producteur ?")::</b>
::raw _("Découvrez nos formations gratuites pour utiliser <b>Cagette Pro</b> ")::
&nbsp;&nbsp;<a href="http://alilo.fr/formations-producteurs" target="_blank" class="btn btn-xs btn-info">C'est parti !</a>
</p>-->
</div>
<!--
<div class="col-md-3" >
::_("FOLLOW US")::
<ul class="cagsocialmedia">
<li class="cagfb">
<a title="Facebook" href="https://www.facebook.com/cagette" target="_blank"> <i class="fa fa-facebook"></i></a>
</li>
<li class="cagtwitter">
<a title="Twitter" href="https://twitter.com/Cagettenet" target="_blank"> <i class="fa fa-twitter"></i></a>
</li>
<li class="cagyoutube">
<a title="Youtube" href="https://www.youtube.com/channel/UC3cvGxAUrbN9oSZmr1oZEaw" target="_blank"> <i class="fa fa-youtube"></i></a>
</li>
<li style="background-color:#333;">
<a title="Github" href="https://github.com/bablukid/cagette" target="_blank"> <i class="fa fa-github"></i></a>
</li>
</ul>
</div>
-->
<!--
<div class="col-md-3">
::_("CONTACT US")::
<ul>
<li>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick"/>
<input type="hidden" name="hosted_button_id" value="S9KT7FQS7P622"/>
<input type="image" src="https://www.paypalobjects.com/fr_FR/FR/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal, le réflexe sécurité pour payer en ligne"/>
<img alt="" border="0" src="https://www.paypalobjects.com/fr_FR/i/scr/pixel.gif" width="1" height="1"/>
</form>
</li>
</ul>
</div>
-->
</div>
<div class="row" id="subfooter">
<!--
::raw _("Cagette.net is made by <a href='https://www.alilo.fr' target='_blank'><img src='/img/alilo-trans-black.png' /></a>")::<br/>
-->
<span>version ::VERSION::</span>
</div>
<div class="row">
<div class="col-md-12">
<!-- SQL LOG -->
<table class="sqlLog table table-bordered" ::cond sqlLog::>
::foreach r sqlLog::
<tr ::attr class if(r.bad) 'badSql'::>
<td>::r.t::ms</td>
<td>::r.length::</td>
<td><a href="#" onclick="javascript:alert('::r.explain::');return false;">Exp</a></td>
<td><a href="#" onclick="javascript:alert('::r.stack::');return false;">Stack</a></td>
<td>::r.sql::</td>
</tr>
::use 'footer.mtt'::
::end::
</table>
</div>
</div>
::if (false && user!=null && user.isAmapManager())::
<script>
// Include the UserVoice JavaScript SDK (only needed once on a page)
UserVoice=window.UserVoice||[];(function(){var uv=document.createElement('script');uv.type='text/javascript';uv.async=true;uv.src='//widget.uservoice.com/sayZ1eIZLfSZUa3IwslHCw.js';var s=document.getElementsByTagName('script')[0];s.parentNode.insertBefore(uv,s)})();
//
// UserVoice Javascript SDK developer documentation:
// https://www.uservoice.com/o/javascript-sdk
//
// Set colors
UserVoice.push(['set', {
accent_color: '#6aba2e',
trigger_color: 'white',
trigger_background_color: '#e2753a'
}]);
// Identify the user and pass traits
// To enable, replace sample data with actual user traits and uncomment the line
UserVoice.push(['identify', {
//email: 'john.doe@example.com', // Users email address
//name: 'John Doe', // Users real name
//created_at: 1364406966, // Unix timestamp for the date the user signed up
//id: 123, // Optional: Unique id of the user (if set, this should not change)
//type: 'Owner', // Optional: segment your users by type
//account: {
// id: 123, // Optional: associate multiple users with a single account
// name: 'Acme, Co.', // Account name
// created_at: 1364406966, // Unix timestamp for the date the account was created
// monthly_rate: 9.99, // Decimal; monthly rate of the account
// ltv: 1495.00, // Decimal; lifetime value of the account
// plan: 'Enhanced' // Plan name for the account
//}
}]);
// Add default trigger to the bottom-right corner of the window:
UserVoice.push(['addTrigger', { mode: 'smartvote', trigger_position: 'bottom-right' }]);
// Or, use your own custom trigger:
//UserVoice.push(['addTrigger', '#id', { mode: 'smartvote' }]);
// Autoprompt for Satisfaction and SmartVote (only displayed under certain conditions)
UserVoice.push(['autoprompt', {}]);
</script>
::end::
::end::
+56
View File
@@ -0,0 +1,56 @@
<div class="row" id="footer">
<div class="col-md-2" >
<img width="120" style="border: white 5px solid;" src="/img/logo-mini.jpg" alt="::_("Cagette.net")::" title="Logo ::_("Cagette.net")::"/>
</div>
<div class="col-md-7" style="padding-top:1em">
Cagette Péi est un logiciel libre qui favorise les circuits courts.<br/>
Il a été adapté pour les besoins des AMAPs sur le marché réunionnais.<br/>
</div>
<div class="col-md-3" >
::_("HELP")::
<ul>
<li>
<a href="https://wiki.cagette.net/doku.php" target="_blank">::_("Documentation")::</a>
</li>
<li>
<a href="https://pad1.zourit.net/p/4a3b09afd25b4fdcb3f0a9598db21e61" target="_blank">Proposer une amélioration</a>
</li>
<li>
<a href="https://pad1.zourit.net/p/4a3b09afd25b4fdcb3f0a9598db21e61" target="_blank">Soumettre une anomalie</a>
</li>
</ul>
</div>
</div>
<div class="row" id="subfooter">
<p><a href="/mentions">MENTIONS LÉGALES</a></p>
<p>
version cagettepei-<a target="_blank" href="https://git.artcode.re/cagetters/cagettepei/src/tag/::VERSION::">::VERSION::</a>
</p>
::if BANDEAU_REGION::
<img src='/img/bandeau_region_france_relance.png' alt='bandeau Région Réunion' width='640'></img>
::end::
</div>
<div class="row">
<div class="col-md-12">
<!-- SQL LOG -->
<table class="sqlLog table table-bordered" ::cond sqlLog::>
::foreach r sqlLog::
<tr ::attr class if(r.bad) 'badSql'::>
<td>::r.t::ms</td>
<td>::r.length::</td>
<td><a href="#" onclick="javascript:alert('::r.explain::');return false;">Exp</a></td>
<td><a href="#" onclick="javascript:alert('::r.stack::');return false;">Stack</a></td>
<td>::r.sql::</td>
</tr>
::end::
</table>
</div>
</div>
+14 -6
View File
@@ -1,6 +1,6 @@
::use 'base.mtt'::
<div class="row header" style="margin-top:10px;">
<div class="col-md-8 col-md-offset-2" style="margin-top:12px;">
<!-- Notifications -->
@@ -185,11 +185,19 @@
</div>
<div class="col-md-12">
<div id="footer">
<a href="::_("http://www.cagette.net")::">::_("Cagette.net, the free software of food direct-selling")::</a>.
</div>
::if user == null::
<script language="javascript">
if (document.cookie.includes("rgpd=true")) console.log("RGPD consent OK");
else {
console.log("no consent YET");
_.cookieConsentBox('::redirect::');
}
</script>
::end::
</div>
</div>
::use 'footer.mtt'::
::end::
::end::
+2 -2
View File
@@ -1,4 +1,4 @@
::use 'design.mtt'::
<!--::use 'design.mtt'::-->
<div class="text-center" style="height:400px;width:100%;">
<h1>
<span class="glyphicon glyphicon-cog"></span>
@@ -14,4 +14,4 @@
</div>
::end::
<!--::end::-->
@@ -0,0 +1,67 @@
::use 'design.mtt'::
<div class="col-md-9">
<div class="article">
<h4>Mentions Légales</h4>
<p>
Ce site web est édité par <b>::name::</b>
</p>
<table class="table table-bordered table-condensed">
<tbody><tr>
<th>Champ</th>
<th>Valeur</th>
</tr>
<tr>
<td>Adresse de courrier électronique</td>
<td>::email::</td>
</tr>
<tr>
<td>Numéro Siren</td>
<td>::siren::</td>
</tr>
<tr>
<td>Numéro Siret</td>
<td>::siret::</td>
</tr>
<tr>
<td>Code NAF / APE</td>
<td>::naf::</td>
</tr>
<tr>
<td>Forme juridique et capital</td>
<td>::juridique::</td>
</tr>
<tr>
<td>Responsable éditorial</td>
<td>::responsable::</td>
</tr>
<tr>
<td>Hébergeur</td>
<td>::raw hebergeur::</td>
</tr>
</tbody>
</table>
</div>
</div>
::end::
+14
View File
@@ -0,0 +1,14 @@
::use 'design.mtt'::
<div class="col-md-12" style="height:500px;">
::if user != null::
consent agreed
::else::
<script language="javascript">
_.cookieConsentBox('::redirect::');
</script>
::end::
</div>
::end::
+1 -51
View File
@@ -1,51 +1 @@
{
"name": "CagettePei",
"description": "le logiciel libre du circuit court",
"license": "AGPL-3.0",
"dependencies": {
"bootstrap": "^3.3.4",
"eonasdan-bootstrap-datetimepicker": "^4.7.14",
"geolib": "^2.0.24",
"haxe-modular": "^0.7.0",
"jquery": "^2.2.4",
"leaflet": "^1.3.1",
"react": "^15.6.1",
"react-bootstrap-typeahead": "1.4.2",
"react-datetime": "^2.9.0",
"react-dom": "^15.6.1",
"react-leaflet": "^1.8.0",
"react-places-autocomplete": "^6.0.2",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2"
},
"devDependencies": {
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babelify": "^7.3.0",
"browserify": "^14.4.0",
"cross-env": "^5.1.1",
"node-sass": "^4.5.3",
"npm-run-all": "^4.1.2",
"uglify-js": "^3.1.9",
"watchify": "^3.9.0"
},
"scripts": {
"build": "npm-run-all --parallel build:*",
"build:js": "haxe cagetteJs.hxml",
"build:sass": "node-sass www/css -o www/css",
"watch:sass": "npm run build:sass -- --watch",
"build2": "babel src -d lib",
"libs:dev": "browserify js/libs/libs.js -o www/js/libs.js -d",
"libs:prod": "cross-env NODE_ENV=production browserify js/libs/libs.js | uglifyjs -c -m > www/js/libs.js",
"test": "haxe testsJS.hxml && node js/test/tests.js",
"prepush": "npm test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/bablukid/cagette.git"
},
"bugs": {
"url": "https://github.com/bablukid/cagette/issues"
},
"version": "1.10.1"
}
{"name": "cagette-pei", "description": "le logiciel libre du circuit court", "license": "AGPL-3.0", "dependencies": {"bootstrap": "^3.3.4", "eonasdan-bootstrap-datetimepicker": "^4.7.14", "geolib": "^2.0.24", "haxe-modular": "^0.7.0", "jquery": "^2.2.4", "leaflet": "^1.3.1", "react": "^15.6.1", "react-bootstrap-typeahead": "1.4.2", "react-datetime": "^2.9.0", "react-dom": "^15.6.1", "react-leaflet": "^1.8.0", "react-places-autocomplete": "^6.0.2", "react-router": "^4.2.0", "react-router-dom": "^4.2.2"}, "devDependencies": {"babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "babelify": "^7.3.0", "browserify": "^14.4.0", "cross-env": "^5.1.1", "node-sass": "^4.5.3", "npm-run-all": "^4.1.2", "uglify-js": "^3.1.9", "watchify": "^3.9.0"}, "scripts": {"build": "npm-run-all --parallel build:*", "build:js": "haxe cagetteJs.hxml", "build:sass": "node-sass www/css -o www/css", "watch:sass": "npm run build:sass -- --watch", "build2": "babel src -d lib", "libs:dev": "browserify js/libs/libs.js -o www/js/libs.js -d", "libs:prod": "cross-env NODE_ENV=production browserify js/libs/libs.js | uglifyjs -c -m > www/js/libs.js", "test": "haxe testsJS.hxml && node js/test/tests.js", "prepush": "npm test"}, "repository": {"type": "git", "url": "git+https://github.com/bablukid/cagette.git"}, "bugs": {"url": "https://github.com/bablukid/cagette/issues"}, "version": "1.16.0"}
+3 -10
View File
@@ -1,5 +1,4 @@
import db.User;
import thx.semver.Version;
import Common;
class App extends sugoi.BaseApp {
@@ -10,13 +9,7 @@ class App extends sugoi.BaseApp {
public var eventDispatcher:hxevents.Dispatcher<Event>;
public var plugins:Array<sugoi.plugin.IPlugIn>;
/**
* Version management
* @doc https://github.com/fponticelli/thx.semver
*/
// public static var VERSION = ([0,9,2] : Version).withPre("july");
// public static var VERSION = ([0,9,2] : Version).withPre(MyMacros.getGitShortSHA(), MyMacros.getGitCommitDate());
public static var VERSION = "cagette-péi " + MyMacros.getGitCommitDate();
public static var VERSION = "cagette-pei"; // empty yet, cf.BaseApp.loadConfig
public function new() {
super();
@@ -210,7 +203,7 @@ class App extends sugoi.BaseApp {
out.set("percent", "Pourcentage");
out.set("pinned", "Mets en avant les produits");
out.set("CagetteNetwork", "Me lister dans l'annuaire des groupes Cagette.net");
out.set("CagetteNetwork", "Me lister dans l'annuaire des groupes");
out.set("unitType", "Unité");
out.set("qt", "Quantité");
out.set("Unit", "Pièce");
@@ -287,7 +280,7 @@ class App extends sugoi.BaseApp {
var e = new sugoi.mail.Mail();
e.setSubject(subject);
e.setRecipient(to);
e.setSender(App.config.get("default_email"), t._("Cagette.net"));
e.setSender(App.config.get("default_email"), t._("CagettePéi"));
var html = App.current.processTemplate("mail/message.mtt", {text: html, group: group});
e.setHtmlBody(html);
App.sendMail(e);
+186 -194
View File
@@ -1,4 +1,5 @@
package controller;
import db.UserContract;
import sugoi.form.elements.DateDropdowns;
import sugoi.form.elements.Input;
@@ -7,14 +8,13 @@ import sugoi.form.Form;
import db.Contract;
import Common;
import plugin.Tutorial;
using Std;
import service.OrderService;
class Contract extends Controller
{
public function new()
{
class Contract extends Controller {
public function new() {
super();
}
@@ -29,58 +29,58 @@ class Contract extends Controller
*/
@tpl("contract/default.mtt")
function doDefault() {
//Create the list of links to change the language
var langs = App.config.get("langs").split(";");
var langNames = App.config.get("langnames").split(";");
var i=0;
// Create the list of links to change the language
var langs = App.config.get("langs", "fr").split(";");
var langNames = App.config.get("langnames", "Français").split(";");
var i = 0;
var langLinks = "";
for (lang in langs)
{
for (lang in langs) {
langLinks += "<li><a href=\"?lang=" + langs[i] + "\">" + langNames[i] + "</a></li>";
i++;
}
view.langLinks = langLinks;
view.langText = langNames[langs.indexOf(app.session.lang)];
//change account lang
if (app.params.exists("lang") && app.user!=null){
// change account lang
if (app.params.exists("lang") && app.user != null) {
app.user.lock();
app.user.lang = app.params.get("lang");
app.user.update();
}
var ua = db.UserAmap.get(app.user, app.user.amap);
if (ua == null) throw Error("/", t._("You are not a member of this group"));
if (ua == null)
throw Error("/", t._("You are not a member of this group"));
var constOrders = null;
var varOrders = new Map<String,Array<db.UserContract>>();
var varOrders = new Map<String, Array<db.UserContract>>();
var a = App.current.user.amap;
var oneMonthAgo = DateTools.delta(Date.now(), -1000.0 * 60 * 60 * 24 * 30);
//constant orders
// constant orders
var contracts = db.Contract.manager.search($type == db.Contract.TYPE_CONSTORDERS && $amap == a && $endDate > oneMonthAgo, false);
constOrders = [];
for ( c in contracts){
for (c in contracts) {
var orders = app.user.getOrdersFromContracts([c]);
if (orders.length == 0) continue;
constOrders.push({contract:c, orders:service.OrderService.prepare(orders) });
if (orders.length == 0)
continue;
constOrders.push({contract: c, orders: service.OrderService.prepare(orders)});
}
//variable orders, grouped by date
// variable orders, grouped by date
var contracts = db.Contract.manager.search($type == db.Contract.TYPE_VARORDER && $amap == a && $endDate > oneMonthAgo, false);
for (c in contracts) {
var ds = c.getDistribs(false);
for (d in ds) {
//store orders in a stringmap like "2015-01-01" => [order1,order2,...]
// store orders in a stringmap like "2015-01-01" => [order1,order2,...]
var k = d.date.toString().substr(0, 10);
var orders = app.user.getOrdersFromDistrib(d);
if (orders.length > 0) {
if (!varOrders.exists(k)) {
varOrders.set(k, Lambda.array(orders));
}else {
} else {
var z = varOrders.get(k).concat(Lambda.array(orders));
varOrders.set(k, z);
}
@@ -88,58 +88,53 @@ class Contract extends Controller
}
}
//final structure
var varOrders2 = new Array<{date:Date,orders:Array<UserOrder>}>();
for ( k in varOrders.keys()) {
// final structure
var varOrders2 = new Array<{date:Date, orders:Array<UserOrder>}>();
for (k in varOrders.keys()) {
var d = new Date(k.split("-")[0].parseInt(), k.split("-")[1].parseInt() - 1, k.split("-")[2].parseInt(), 0, 0, 0);
var orders = service.OrderService.prepare( Lambda.list(varOrders[k]) );
var orders = service.OrderService.prepare(Lambda.list(varOrders[k]));
varOrders2.push({date:d,orders:orders});
varOrders2.push({date: d, orders: orders});
}
//sort by date desc
// sort by date desc
varOrders2.sort(function(b, a) {
return Math.round(a.date.getTime()/1000)-Math.round(b.date.getTime()/1000);
return Math.round(a.date.getTime() / 1000) - Math.round(b.date.getTime() / 1000);
});
view.varOrders = varOrders2;
view.constOrders = constOrders;
// tutorials
if (app.user.isAmapManager()) {
//actions
if (app.params.exists('startTuto') ) {
//start a tuto
// actions
if (app.params.exists('startTuto')) {
// start a tuto
app.user.lock();
var t = app.params.get('startTuto');
app.user.tutoState = {name:t,step:0};
app.user.tutoState = {name: t, step: 0};
app.user.update();
}
// tuto state
var tutos = new Array<{name:String, completion:Float, key:String}>();
//tuto state
var tutos = new Array<{name:String,completion:Float,key:String}>();
for ( k in Tutorial.all().keys() ) {
for (k in Tutorial.all().keys()) {
var t = Tutorial.all().get(k);
var completion = null;
if (app.user.tutoState!=null && app.user.tutoState.name == k) completion = app.user.tutoState.step / t.steps.length;
if (app.user.tutoState != null && app.user.tutoState.name == k)
completion = app.user.tutoState.step / t.steps.length;
tutos.push( { name:t.name, completion:completion , key:k } );
tutos.push({name: t.name, completion: completion, key: k});
}
view.tutos = tutos;
}
//should be able to stop tuto in any case
// should be able to stop tuto in any case
if (app.params.exists('stopTuto')) {
//stopped tuto from a tuto window
// stopped tuto from a tuto window
app.user.lock();
app.user.tutoState = null;
app.user.update();
@@ -155,28 +150,29 @@ class Contract extends Controller
*/
@tpl("form.mtt")
function doEdit(c:db.Contract) {
view.category = 'contractadmin';
if (!app.user.isContractManager(c)) throw Error('/', t._("Forbidden action"));
if (!app.user.isContractManager(c))
throw Error('/', t._("Forbidden action"));
view.title = t._("Edit contract ::contractName::",{contractName:c.name});
view.title = t._("Edit contract ::contractName::", {contractName: c.name});
var group = c.amap;
var currentContact = c.contact;
var form = Form.fromSpod(c);
form.removeElement( form.getElement("amapId") );
form.removeElement(form.getElement("amapId"));
form.removeElement(form.getElement("type"));
form.getElement("userId").required = true;
app.event(EditContract(c,form));
app.event(EditContract(c, form));
if (form.checkToken()) {
form.toSpod(c);
c.amap = group;
//checks & warnings
if (c.hasPercentageOnOrders() && c.percentageValue==null) throw Error("/contract/edit/"+c.id, t._("If you would like to add fees to the order, define a rate (%) and a label."));
// checks & warnings
if (c.hasPercentageOnOrders() && c.percentageValue == null)
throw Error("/contract/edit/" + c.id, t._("If you would like to add fees to the order, define a rate (%) and a label."));
if (c.hasStockManagement()) {
for (p in c.getProducts()) {
@@ -187,24 +183,23 @@ class Contract extends Controller
}
}
//no stock mgmt for constant orders
if (c.hasStockManagement() && c.type==db.Contract.TYPE_CONSTORDERS) {
// no stock mgmt for constant orders
if (c.hasStockManagement() && c.type == db.Contract.TYPE_CONSTORDERS) {
c.flags.unset(ContractFlags.StockManagement);
app.session.addMessage(t._("Managing stock is not available for CSA contracts"), true);
}
c.update();
//update rights
if ( c.contact != null && (currentContact==null || c.contact.id!=currentContact.id) ) {
// update rights
if (c.contact != null && (currentContact == null || c.contact.id != currentContact.id)) {
var ua = db.UserAmap.get(c.contact, app.user.amap, true);
ua.giveRight(ContractAdmin(c.id));
ua.giveRight(Messages);
ua.giveRight(Membership);
ua.update();
//remove rights to old contact
// remove rights to old contact
if (currentContact != null) {
var x = db.UserAmap.get(currentContact, c.amap, true);
if (x != null) {
@@ -212,10 +207,9 @@ class Contract extends Controller
x.update();
}
}
}
throw Ok("/contractAdmin/view/"+c.id, t._("Contract updated"));
throw Ok("/contractAdmin/view/" + c.id, t._("Contract updated"));
}
view.form = form;
@@ -223,8 +217,7 @@ class Contract extends Controller
@tpl("contract/insertChoose.mtt")
function doInsertChoose() {
//checkToken();
// checkToken();
}
/**
@@ -232,27 +225,29 @@ class Contract extends Controller
*/
@tpl("form.mtt")
function doInsert(?type:Int) {
if (!app.user.canManageAllContracts()) throw Error('/', t._("Forbidden action"));
if (type == null) throw Redirect('/contract/insertChoose');
if (!app.user.canManageAllContracts())
throw Error('/', t._("Forbidden action"));
if (type == null)
throw Redirect('/contract/insertChoose');
view.title = if (type == db.Contract.TYPE_CONSTORDERS)t._("Create a contract with fixed orders") else t._("Create a contract with variable orders");
view.title = if (type == db.Contract.TYPE_CONSTORDERS) t._("Create a contract with fixed orders") else t._("Create a contract with variable orders");
var c = new db.Contract();
var form = Form.fromSpod(c);
form.removeElement( form.getElement("amapId") );
form.removeElement(form.getElement("amapId"));
form.removeElement(form.getElement("type"));
form.getElement("userId").required = true;
if (form.checkToken()) {
form.toSpod(c);
c.amap = app.user.amap;
//trace(app.user.amap);
//trace(c.amap);
// trace(app.user.amap);
// trace(c.amap);
c.type = type;
c.insert();
//right
// right
if (c.contact != null) {
var ua = db.UserAmap.get(c.contact, app.user.amap, true);
ua.giveRight(ContractAdmin(c.id));
@@ -261,7 +256,7 @@ class Contract extends Controller
ua.update();
}
throw Ok("/contractAdmin/view/"+c.id, t._("New contract created"));
throw Ok("/contractAdmin/view/" + c.id, t._("New contract created"));
}
view.form = form;
@@ -271,24 +266,25 @@ class Contract extends Controller
* Delete a contract (... and its products, orders & distributions)
*/
function doDelete(c:db.Contract) {
if (!app.user.canManageAllContracts()) throw Error("/contractAdmin", t._("You don't have the authorization to remove a contract"));
if (!app.user.canManageAllContracts())
throw Error("/contractAdmin", t._("You don't have the authorization to remove a contract"));
if (checkToken()) {
c.lock();
//check if there is orders in this contract
// check if there is orders in this contract
var products = c.getProducts();
var orders = db.UserContract.manager.search($productId in Lambda.map(products, function(p) return p.id));
var qt = 0.0;
for ( o in orders) qt += o.quantity; //there could be "zero c qt" orders
for (o in orders)
qt += o.quantity; // there could be "zero c qt" orders
if (qt > 0) {
throw Error("/contractAdmin", t._("You cannot delete this contract because some orders are linked to it."));
}
//remove admin rights and delete contract
if(c.contact!=null){
// remove admin rights and delete contract
if (c.contact != null) {
var ua = db.UserAmap.get(c.contact, c.amap, true);
if (ua != null) {
ua.removeRight(ContractAdmin(c.id));
@@ -314,89 +310,89 @@ class Contract extends Controller
*
*/
@tpl("contract/order.mtt")
function doOrder(c:db.Contract ) {
//checks
if (app.user.amap.hasPayments()) throw Redirect("/contract/orderAndPay/" + c.id);
if (app.user.amap.hasShopMode()) throw Redirect("/shop");
if (!c.isUserOrderAvailable()) throw Error("/", t._("This contract is not opened for orders"));
function doOrder(c:db.Contract) {
// checks
if (app.user.amap.hasPayments())
throw Redirect("/contract/orderAndPay/" + c.id);
if (app.user.amap.hasShopMode())
throw Redirect("/shop");
if (!c.isUserOrderAvailable())
throw Error("/", t._("This contract is not opened for orders"));
var distributions = [];
// If its a varying contract, we display a column by distribution
if (c.type == db.Contract.TYPE_VARORDER) {
distributions = db.Distribution.getOpenToOrdersDeliveries(c);
}else{
} else {
distributions = [null];
}
//list of distribs with a list of product and optionnaly an order
var userOrders = new Array< {distrib:db.Distribution,datas:Array<{order:db.UserContract,product:db.Product}>} >();
// list of distribs with a list of product and optionnaly an order
var userOrders = new Array<{distrib:db.Distribution, datas:Array<{order:db.UserContract, product:db.Product}>}>();
var products = c.getProducts();
if ( c.type == db.Contract.TYPE_VARORDER ){
for ( d in distributions){
if (c.type == db.Contract.TYPE_VARORDER) {
for (d in distributions) {
var datas = [];
for ( p in products) {
var ua = { order:null, product:p };
for (p in products) {
var ua = {order: null, product: p};
var order = db.UserContract.manager.select($user == app.user && $productId == p.id && $distributionId==d.id, true);
var order = db.UserContract.manager.select($user == app.user && $productId == p.id && $distributionId == d.id, true);
if (order != null) ua.order = order;
if (order != null)
ua.order = order;
datas.push(ua);
}
userOrders.push({distrib:d,datas:datas});
userOrders.push({distrib: d, datas: datas});
}
}else{
} else {
var datas = [];
for ( p in products) {
var ua = { order:null, product:p };
for (p in products) {
var ua = {order: null, product: p};
var order = db.UserContract.manager.select($user == app.user && $productId == p.id, true);
if (order != null) ua.order = order;
if (order != null)
ua.order = order;
datas.push(ua);
}
userOrders.push({distrib:null,datas:datas});
userOrders.push({distrib: null, datas: datas});
}
//form check
// form check
if (checkToken()) {
//get dsitrib if needed
//var distrib : db.Distribution = null;
//if (c.type == db.Contract.TYPE_VARORDER) {
//distrib = db.Distribution.manager.get(Std.parseInt(app.params.get("distribution")), false);
//}
// get dsitrib if needed
// var distrib : db.Distribution = null;
// if (c.type == db.Contract.TYPE_VARORDER) {
// distrib = db.Distribution.manager.get(Std.parseInt(app.params.get("distribution")), false);
// }
for (k in app.params.keys()) {
if (k.substr(0, 1) != "d") continue;
if (k.substr(0, 1) != "d")
continue;
var qt = app.params.get(k);
if (qt == "") continue;
if (qt == "")
continue;
var pid = null;
var did = null;
try{
try {
pid = Std.parseInt(k.split("-")[1].substr(1));
did = Std.parseInt(k.split("-")[0].substr(1));
}catch (e:Dynamic){trace("unable to parse key "+k); }
} catch (e:Dynamic) {
trace("unable to parse key " + k);
}
//find related element in userOrders
// find related element in userOrders
var uo = null;
for ( x in userOrders){
if (x.distrib!=null && x.distrib.id != did) {
for (x in userOrders) {
if (x.distrib != null && x.distrib.id != did) {
continue;
}else{
for (a in x.datas){
if (a.product.id == pid){
} else {
for (a in x.datas) {
if (a.product.id == pid) {
uo = a;
break;
}
@@ -404,43 +400,43 @@ class Contract extends Controller
}
}
if (uo == null) throw t._("Could not find the product ::produ:: and delivery ::deliv::", {produ:pid, deliv:did});
if (uo == null)
throw t._("Could not find the product ::produ:: and delivery ::deliv::", {produ: pid, deliv: did});
var q = 0.0;
if (uo.product.hasFloatQt ) {
if (uo.product.hasFloatQt) {
var param = StringTools.replace(qt, ",", ".");
q = Std.parseFloat(param);
}else {
} else {
q = Std.parseInt(qt);
}
if (uo.order != null) {
OrderService.edit(uo.order, q);
}else {
} else {
OrderService.make(app.user, q, uo.product, did);
}
}
throw Ok("/contract/order/"+c.id, t._("Your order has been updated"));
throw Ok("/contract/order/" + c.id, t._("Your order has been updated"));
}
view.c = view.contract = c;
view.userOrders = userOrders;
}
/**
* Make an order by contract ( standard mode ) + payment process
*/
@tpl("contract/orderAndPay.mtt")
function doOrderAndPay(c:db.Contract ) {
//checks
if (!app.user.amap.hasPayments()) throw Redirect("/contract/order/" + c.id);
if (app.user.amap.hasShopMode()) throw Redirect("/");
if (!c.isUserOrderAvailable()) throw Error("/", t._("This contract is not opened for orders"));
function doOrderAndPay(c:db.Contract) {
// checks
if (!app.user.amap.hasPayments())
throw Redirect("/contract/order/" + c.id);
if (app.user.amap.hasShopMode())
throw Redirect("/");
if (!c.isUserOrderAvailable())
throw Error("/", t._("This contract is not opened for orders"));
var distributions = [];
/* If its a varying contract, we display a column by distribution*/
@@ -448,64 +444,64 @@ class Contract extends Controller
distributions = db.Distribution.getOpenToOrdersDeliveries(c);
}
//list of distribs with a list of product and optionnaly an order
var userOrders = new Array< {distrib:db.Distribution,datas:Array<{order:db.UserContract,product:db.Product}>} >();
// list of distribs with a list of product and optionnaly an order
var userOrders = new Array<{distrib:db.Distribution, datas:Array<{order:db.UserContract, product:db.Product}>}>();
var products = c.getProducts();
for ( d in distributions){
for (d in distributions) {
var datas = [];
for ( p in products) {
var ua = { order:null, product:p };
for (p in products) {
var ua = {order: null, product: p};
var order : db.UserContract = null;
var order:db.UserContract = null;
if (c.type == db.Contract.TYPE_VARORDER) {
order = db.UserContract.manager.select($user == app.user && $productId == p.id && $distributionId==d.id, true);
}else {
order = db.UserContract.manager.select($user == app.user && $productId == p.id && $distributionId == d.id, true);
} else {
order = db.UserContract.manager.select($user == app.user && $productId == p.id, true);
}
if (order != null) ua.order = order;
if (order != null)
ua.order = order;
datas.push(ua);
}
userOrders.push({distrib:d,datas:datas});
userOrders.push({distrib: d, datas: datas});
}
//form check
// form check
if (checkToken()) {
//get distrib if needed
// get distrib if needed
var distrib = null;
if (c.type == db.Contract.TYPE_VARORDER) {
distrib = db.Distribution.manager.get(Std.parseInt(app.params.get("distribution")), false);
}
var orders : OrderInSession = {products:[],userId:app.user.id,total:0};
var orders:OrderInSession = {products: [], userId: app.user.id, total: 0};
for (k in app.params.keys()) {
if (k.substr(0, 1) != "d") continue;
if (k.substr(0, 1) != "d")
continue;
var qt = app.params.get(k);
if (qt == "") continue;
if (qt == "")
continue;
var pid = null;
var did = null;
try{
try {
pid = Std.parseInt(k.split("-")[1].substr(1));
did = Std.parseInt(k.split("-")[0].substr(1));
}catch (e:Dynamic){
trace("unable to parse key "+k);
} catch (e:Dynamic) {
trace("unable to parse key " + k);
}
//find related element in userOrders
// find related element in userOrders
var uo = null;
for ( x in userOrders){
if (x.distrib!=null && x.distrib.id != did) {
for (x in userOrders) {
if (x.distrib != null && x.distrib.id != did) {
continue;
}else{
for (a in x.datas){
if (a.product.id == pid){
} else {
for (a in x.datas) {
if (a.product.id == pid) {
uo = a;
break;
}
@@ -513,58 +509,53 @@ class Contract extends Controller
}
}
if (uo == null) throw t._("Could not find the product ::produ:: and delivery ::deliv::", {produ:pid, deliv:did});
if (uo == null)
throw t._("Could not find the product ::produ:: and delivery ::deliv::", {produ: pid, deliv: did});
//quantity
// quantity
var q = 0.0;
if (uo.product.hasFloatQt ) {
if (uo.product.hasFloatQt) {
var param = StringTools.replace(qt, ",", ".");
q = Std.parseFloat(param);
}else {
} else {
q = Std.parseInt(qt);
}
orders.products.push({productId:pid, quantity:q, distributionId:did});
orders.products.push({productId: pid, quantity: q, distributionId: did});
var p = db.Product.manager.get(pid, false);
orders.total += p.getPrice() * q;
}
App.current.session.data.order = orders;
//Go to payments page
// Go to payments page
if (c.type == db.Contract.TYPE_CONSTORDERS) {
throw Ok("/contract/order/"+c.id, t._("Your CSA order has been saved"));
}else{
throw Ok("/contract/order/" + c.id, t._("Your CSA order has been saved"));
} else {
throw Ok("/transaction/pay/", t._("In order to save your order, please choose a means of payment."));
}
}
view.c = view.contract = c;
view.userOrders = userOrders;
}
/**
* A user edit an order for a multidistrib.
*/
@tpl("contract/orderByDate.mtt")
function doEditOrderByDate(date:Date) {
if (app.user.amap.hasPayments()) {
//when payments are active, the user cannot modify his order
// when payments are active, the user cannot modify his order
throw Redirect("/");
}
// cannot edit order if date is in the past
if (Date.now().getTime() > date.getTime()) {
var msg = t._("This delivery has already taken place, you can no longer modify the order.");
if (app.user.isContractManager()) msg += t._("<br/>As the manager of the contract you can modify the order from this page: <a href='/contractAdmin'>Management of contracts</a>");
if (app.user.isContractManager())
msg += t._("<br/>As the manager of the contract you can modify the order from this page: <a href='/contractAdmin'>Management of contracts</a>");
throw Error("/contract", msg);
}
@@ -574,39 +565,40 @@ class Contract extends Controller
var d2 = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
var cids = Lambda.map(app.user.amap.getActiveContracts(true), function(c) return c.id);
var distribs = db.Distribution.manager.search(($contractId in cids) && $date >= d1 && $date <=d2 , false);
var orders = db.UserContract.manager.search($userId==app.user.id && $distributionId in Lambda.map(distribs,function(d)return d.id) );
var distribs = db.Distribution.manager.search(($contractId in cids) && $date >= d1 && $date <= d2, false);
var orders = db.UserContract.manager.search($userId == app.user.id
&& $distributionId in Lambda.map(distribs, function(d) return d.id));
view.orders = service.OrderService.prepare(orders);
view.date = date;
//form check
// form check
if (checkToken()) {
var orders_out = [];
for (k in app.params.keys()) {
var param = app.params.get(k);
if (k.substr(0, "product".length) == "product") {
//trouve le produit dans userOrders
// trouve le produit dans userOrders
var pid = Std.parseInt(k.substr("product".length));
var order = Lambda.find(orders, function(uo) return uo.product.id == pid);
if (order == null) throw t._("Error, could not find the order");
if (order == null)
throw t._("Error, could not find the order");
var q = 0.0;
if (order.product.hasFloatQt ) {
if (order.product.hasFloatQt) {
param = StringTools.replace(param, ",", ".");
q = Std.parseFloat(param);
}else {
} else {
q = Std.parseInt(param);
}
var quantity = Math.abs( q==null?0:q );
var quantity = Math.abs(q == null ? 0 : q);
if ( order.distribution.canOrderNow() ) {
//met a jour la commande
if (order.distribution.canOrderNow()) {
// met a jour la commande
var o = OrderService.edit(order, quantity);
if(o!=null) orders_out.push( o );
if (o != null)
orders_out.push(o);
}
}
}
-2
View File
@@ -19,8 +19,6 @@ class ContractAdmin extends Controller {
if (!app.user.isContractManager())
throw Error("/", t._("You don't have the authorization to manage contracts"));
view.nav = ["contractadmin"];
App.log("first message");
}
public function sendNav(c) {
+1 -1
View File
@@ -54,7 +54,7 @@ class Group extends controller.Controller
form.addElement(new StringInput("userLastName", t._("Your lastname") ,"",true));
form.addElement(new StringInput("userEmail", t._("Your e-mail"), "", true));
}
form.addElement(new sugoi.form.elements.TextArea("msg", t._("Leave a message")));
form.addElement(new sugoi.form.elements.TextArea("msg", t._("Leave a message"),"",false));
if (form.isValid()){
try{
+39 -43
View File
@@ -1,4 +1,5 @@
package controller;
import db.Distribution;
import db.UserContract;
import haxe.Json;
@@ -9,12 +10,10 @@ import Common;
import tools.ArrayTool;
class Main extends Controller {
/**
* public pages
*/
function doGroup(d:haxe.web.Dispatch){
function doGroup(d:haxe.web.Dispatch) {
d.dispatch(new controller.Group());
}
@@ -26,49 +25,52 @@ class Main extends Controller {
view.category = 'home';
var group = app.getCurrentGroup();
if ( app.user!=null && group == null) {
if (app.user != null && group == null) {
throw Redirect("/user/choose");
}else if (app.user == null && (group==null || group.regOption!=db.Amap.RegOption.Open) ) {
} else if (app.user == null && (group == null || group.regOption != db.Amap.RegOption.Open)) {
if (db.Amap.manager.get(1, false) != null)
throw Redirect("/group/1");
else
throw Redirect("/user/login");
}
view.amap = group;
//contract with open orders
// contract with open orders
var openContracts = Lambda.filter(group.getActiveContracts(), function(c) return c.isUserOrderAvailable());
view.openContracts = openContracts;
//register to become "distributor"
view.contractsWithDistributors = app.user==null ? [] : Lambda.filter(app.user.amap.getActiveContracts(), function(c) return c.distributorNum > 0);
// register to become "distributor"
view.contractsWithDistributors = app.user == null ? [] : Lambda.filter(app.user.amap.getActiveContracts(), function(c) return c.distributorNum > 0);
//freshly created group
// freshly created group
view.newGroup = app.session.data.newGroup == true;
var n = Date.now();
var now = new Date(n.getFullYear(), n.getMonth(), n.getDate(), 0, 0, 0);
var in3Month = DateTools.delta(now, 1000.0 * 60 * 60 * 24 * 30 * 3);
var distribs = MultiDistrib.getFromTimeRange(group,now,in3Month);
var distribs = MultiDistrib.getFromTimeRange(group, now, in3Month);
view.distribs = distribs;
//view functions
// view functions
view.getWhosTurn = function(orderId:Int, distrib:Distribution) {
return db.UserContract.manager.get(orderId, false).getWhosTurn(distrib);
}
//event for additionnal blocks on home page
// event for additionnal blocks on home page
var e = Blocks([], "home");
app.event(e);
view.blocks = e.getParameters()[0];
//message if phone is required
if(app.user!=null && app.user.amap.flags.has(db.Amap.AmapFlags.PhoneRequired) && app.user.phone==null){
app.session.addMessage(t._("Members of this group should provide a phone number. <a href='/account/edit'>Please click here to update your account</a>."),true);
// message if phone is required
if (app.user != null && app.user.amap.flags.has(db.Amap.AmapFlags.PhoneRequired) && app.user.phone == null) {
app.session.addMessage(t._("Members of this group should provide a phone number. <a href='/account/edit'>Please click here to update your account</a>."),
true);
}
}
}
//login and stuff
// login and stuff
function doUser(d:Dispatch) {
d.dispatch(new controller.User());
}
@@ -81,26 +83,19 @@ class Main extends Controller {
* JSON REST API Entry point
*/
function doApi(d:Dispatch) {
try {
d.dispatch(new controller.Api());
}catch (e:tink.core.Error){
//manage tink Errors (service errors)
} catch (e:tink.core.Error) {
// manage tink Errors (service errors)
sugoi.Web.setReturnCode(e.code);
Sys.print(Json.stringify( {error:{code:e.code,message:e.message,stack:e.exceptionStack}} ));
}catch (e:Dynamic){
//manage other errors
Sys.print(Json.stringify({error: {code: e.code, message: e.message, stack: e.exceptionStack}}));
} catch (e:Dynamic) {
// manage other errors
sugoi.Web.setReturnCode(500);
var stack = if ( App.config.DEBUG ) haxe.CallStack.toString(haxe.CallStack.exceptionStack()) else "";
var stack = if (App.config.DEBUG) haxe.CallStack.toString(haxe.CallStack.exceptionStack()) else "";
App.current.logError(e, stack);
Sys.print(Json.stringify( {error:{code:500,message : Std.string(e), stack:stack }} ));
Sys.print(Json.stringify({error: {code: 500, message: Std.string(e), stack: stack}}));
}
}
@tpl("cssDemo.mtt")
@@ -113,15 +108,13 @@ class Main extends Controller {
d.dispatch(new controller.Install());
}
function doP(d:Dispatch) {
/*
* Invalid array access
Stack (ADMIN|DEBUG)
Stack (ADMIN|DEBUG)
Called from C:\HaxeToolkit\haxe\std/haxe/web/Dispatch.hx line 463
Called from controller/Main.hx line 117
Called from C:\HaxeToolkit\haxe\std/haxe/web/Dispatch.hx line 463
Called from controller/Main.hx line 117
*
var plugin = d.parts.shift();
for ( p in App.plugins) {
@@ -139,7 +132,6 @@ Called from controller/Main.hx line 117
d.dispatch(new controller.Plugin());
}
@logged
function doMember(d:Dispatch) {
view.category = 'members';
@@ -148,10 +140,17 @@ Called from controller/Main.hx line 117
@logged
function doStats(d:Dispatch) {
App.log('doStats called');
view.category = 'stats';
d.dispatch(new Stats());
}
function doMentions(d:Dispatch) {
App.log('do Mentions called');
view.category = 'mentions';
d.dispatch(new MentionsLegales());
}
@logged
function doAccount(d:Dispatch) {
view.category = 'account';
@@ -237,8 +236,7 @@ Called from controller/Main.hx line 117
}
@logged
function doValidate(date:Date, place:db.Place, user:db.User, d:haxe.web.Dispatch){
function doValidate(date:Date, place:db.Place, user:db.User, d:haxe.web.Dispatch) {
var v = new controller.Validate();
v.date = date;
v.place = place;
@@ -253,9 +251,7 @@ Called from controller/Main.hx line 117
@admin
function doDb(d:Dispatch) {
d.parts = []; //disable haxe.web.Dispatch
d.parts = []; // disable haxe.web.Dispatch
sys.db.Admin.handler();
}
}
+19
View File
@@ -0,0 +1,19 @@
package controller;
class MentionsLegales extends Controller {
public function new() {
super();
}
@tpl("mentions_legales/default.mtt")
function doDefault() {
view.name = App.config.get("legal.name");
view.email = App.config.get("legal.email");
view.siren = App.config.get("legal.siren");
view.siret = App.config.get("legal.siret");
view.naf = App.config.get("legal.naf");
view.juridique = App.config.get("legal.juridique");
view.responsable = App.config.get("legal.responsable");
view.hebergeur = App.config.get("legal.hebergeur");
}
}
+7 -5
View File
@@ -31,8 +31,8 @@ class Messages extends Controller {
var lists = getLists();
form.addElement(new StringInput("senderName", t._("Sender name"), senderName, true));
form.addElement(new StringInput("senderMail", t._("Sender E-Mail"), senderMail, true));
form.addElement(new StringSelect("list", t._("Recipients"), lists, "1", true, null, "style='width:500px;'"));
form.addElement(new StringInput("subject", t._("Subject:"), "", false, null, "style='width:500px;'"));
form.addElement(new StringSelect("list", t._("Recipients"), lists, "3", true, null, "style='width:500px;'"));
form.addElement(new StringInput("subject", t._("Subject:"), "", true, null, "style='width:500px;'"));
form.addElement(new TextArea("text", t._("Message:"), "", false, null, "style='width:500px;height:350px;'"));
if (form.checkToken()) {
@@ -52,7 +52,7 @@ class Messages extends Controller {
// send mail confirmation link
var e = new sugoi.mail.Mail();
e.setSender(App.config.get("default_email"), t._("Cagette.net"));
e.setSubject(subject);
e.setSubject('[cagettepei] $subject');
var replyTo = form.getValueOf("senderMail");
var replyToName = form.getValueOf("senderName");
@@ -63,9 +63,13 @@ class Messages extends Controller {
e.addRecipient(x);
var text:String = form.getValueOf("text");
if (text == null)
text = "";
var html = app.processTemplate("mail/message.mtt", {text: text, group: app.user.amap, list: getListName(listId)});
e.setHtmlBody(html);
App.log('text=[$text]');
App.log('html= ${e.getHtmlBody()}');
App.sendMail(e, app.user.getAmap(), listId, app.user);
// store message
@@ -82,8 +86,6 @@ class Messages extends Controller {
lm.insert();
throw Ok("/messages", t._("The message has been sent"));
} else {
App.log('Administrator #${app.user.id} <${senderName}> prepares sending an email from choices list');
}
view.form = form;
+86 -86
View File
@@ -1,4 +1,5 @@
package controller;
import haxe.crypto.Md5;
import sugoi.form.elements.Input;
import sugoi.form.Form;
@@ -7,57 +8,65 @@ import sugoi.form.elements.StringInput;
import sugoi.form.validators.EmailValidator;
import ufront.mail.*;
class User extends Controller
{
public function new()
{
class User extends Controller {
public function new() {
super();
}
@tpl("user/default.mtt")
function doDefault() {
}
function doDefault() {}
@tpl("user/login.mtt")
function doLogin() {
if (App.current.user != null) {
throw Redirect('/');
}
//if its needed to redirect after login
if (app.params.exists("redirect")){
// if its needed to redirect after login
if (app.params.exists("redirect")) {
view.redirect = app.params.exists("redirect");
}else{
} else {
view.redirect = "/";
}
}
@tpl("user/cookieConsent.mtt")
function doCookieConsent() {
App.log("Cookie Consent called!");
// if (App.current.user != null) {
// throw Redirect('/');
// }
// if its needed to redirect after login
if (app.params.exists("redirect")) {
view.redirect = app.params.exists("redirect");
} else {
view.redirect = "/";
}
}
/**
* Choose which group to connect to.
*/
@logged
@tpl("user/choose.mtt")
function doChoose(?args: { amap:db.Amap } ) {
if (app.user == null) throw t._("You are not connected");
function doChoose(?args:{amap:db.Amap}) {
if (app.user == null)
throw t._("You are not connected");
var amaps = db.UserAmap.manager.search($user == app.user, false);
if (amaps.length == 1 && !app.params.exists("show")) {
//qu'une amap
// qu'une amap
app.session.data.amapId = amaps.first().amap.id;
throw Redirect('/');
}else{
view.noGroup = true; //force template to not display current group
} else {
view.noGroup = true; // force template to not display current group
}
if (args!=null && args.amap!=null) {
//select a group
var which = app.session.data==null ? 0 : app.session.data.whichUser ;
if (args != null && args.amap != null) {
// select a group
var which = app.session.data == null ? 0 : app.session.data.whichUser;
app.session.data.order = null;
app.session.data.newGroup = null;
app.session.data.amapId = args.amap.id;
@@ -68,7 +77,6 @@ class User extends Controller
view.amaps = amaps;
view.wl = db.WaitingList.manager.search($user == app.user, false);
#if plugins
view.pros = pro.db.PUserCompany.getCompanies(app.user);
#end
@@ -84,75 +92,76 @@ class User extends Controller
* when password is forgotten
*/
@tpl("user/forgottenPassword.mtt")
function doForgottenPassword(?key:String, ?u:db.User){
//STEP 1
function doForgottenPassword(?key:String, ?u:db.User) {
// STEP 1
var step = 1;
var error : String = null;
var error:String = null;
var url = "/user/forgottenPassword";
//ask for mail
// ask for mail
var askmailform = new Form("askemail");
askmailform.addElement(new StringInput("email", t._("Please key-in your E-Mail address"),null,true));
askmailform.addElement(new StringInput("email", t._("Please key-in your E-Mail address"), null, true));
//change pass form
// change pass form
var chpassform = new Form("chpass");
var pass1 = new StringInput("pass1", t._("Your new password"),null,true);
var pass1 = new StringInput("pass1", t._("Your new password"), null, true);
pass1.password = true;
chpassform.addElement(pass1);
var pass2 = new StringInput("pass2", t._("Again your new password"),null,true);
var pass2 = new StringInput("pass2", t._("Again your new password"), null, true);
pass2.password = true;
chpassform.addElement(pass2);
var uid = new IntInput("uid","uid", u == null?null:u.id);
var uid = new IntInput("uid", "uid", u == null ? null : u.id);
uid.inputType = ITHidden;
chpassform.addElement(uid);
if (askmailform.isValid()) {
//STEP 2
//send password renewal email
// STEP 2
// send password renewal email
step = 2;
var email :String = askmailform.getValueOf("email");
var email:String = askmailform.getValueOf("email");
var user = db.User.manager.select(email == $email, false);
//could be user 2
if(user==null) user = db.User.manager.select(email == $email2, false);
// could be user 2
if (user == null)
user = db.User.manager.select(email == $email2, false);
//user not found
if (user == null) throw Error(url, t._("This E-mail is not linked to a known account"));
// user not found
if (user == null)
throw Error(url, t._("This E-mail is not linked to a known account"));
//create token
var token = haxe.crypto.Md5.encode("chp"+Std.random(1000000000));
// create token
var token = haxe.crypto.Md5.encode("chp" + Std.random(1000000000));
sugoi.db.Cache.set(token, user.id, 60 * 60 * 24 * 30);
var m = new sugoi.mail.Mail();
m.setSender(App.config.get("default_email"), t._("Cagette.net"));
m.setRecipient(email, user.name);
m.setSubject( "["+App.config.NAME+"] : "+t._("Password change"));
m.setHtmlBody( app.processTemplate('mail/forgottenPassword.mtt', { user:user, link:'http://' + App.config.HOST + '/user/forgottenPassword/'+token+"/"+user.id }) );
m.setSubject("[" + App.config.NAME + "] " + t._("Password change"));
m.setHtmlBody(app.processTemplate('mail/forgottenPassword.mtt',
{user: user, link: 'http://' + App.config.HOST + '/user/forgottenPassword/' + token + "/" + user.id}));
App.sendMail(m);
}
if (key != null && u!=null) {
//check key and propose to change pass
if (key != null && u != null) {
// check key and propose to change pass
step = 3;
if ( u.id == sugoi.db.Cache.get(key) ) {
if (u.id == sugoi.db.Cache.get(key)) {
view.form = chpassform;
}else {
} else {
error = t._("Invalid request");
}
}
if (chpassform.isValid()) {
//change pass
// change pass
step = 4;
if ( chpassform.getValueOf("pass1") == chpassform.getValueOf("pass2")) {
var uid = Std.parseInt( chpassform.getValueOf("uid") );
if (chpassform.getValueOf("pass1") == chpassform.getValueOf("pass2")) {
var uid = Std.parseInt(chpassform.getValueOf("uid"));
var user = db.User.manager.get(uid, true);
var pass = chpassform.getValueOf("pass1");
user.setPass(pass);
@@ -161,20 +170,21 @@ class User extends Controller
var m = new sugoi.mail.Mail();
m.setSender(App.config.get("default_email"), t._("Cagette.net"));
m.setRecipient(user.email, user.name);
if(user.email2!=null) m.setRecipient(user.email2, user.name);
m.setSubject( "["+App.config.NAME+"] : "+t._("New password confirmed"));
if (user.email2 != null)
m.setRecipient(user.email2, user.name);
m.setSubject("[" + App.config.NAME + "] : " + t._("New password confirmed"));
var emails = [user.email];
if(user.email2!=null) emails.push(user.email2);
if (user.email2 != null)
emails.push(user.email2);
var params = {
user:user,
emails:emails.join(", "),
password:pass,
NAME:App.config.NAME
user: user,
emails: emails.join(", "),
password: pass,
NAME: App.config.NAME
}
m.setHtmlBody( app.processTemplate('mail/newPasswordConfirmed.mtt', params) );
m.setHtmlBody(app.processTemplate('mail/newPasswordConfirmed.mtt', params));
App.sendMail(m);
}else {
} else {
error = t._("You must key-in two times the same password");
}
}
@@ -187,20 +197,18 @@ class User extends Controller
view.error = error;
}
/**
* generate a custom key for transactionnal emails, valid during the current day
*/
//function getKey(m:db.User) {
//return haxe.crypto.Md5.encode(App.config.get("key")+m.email+(Date.now().getDate())).substr(0,12);
//}
// function getKey(m:db.User) {
// return haxe.crypto.Md5.encode(App.config.get("key")+m.email+(Date.now().getDate())).substr(0,12);
// }
@logged
@tpl("form.mtt")
function doDefinePassword(?key:String, ?u:db.User){
if (app.user.isFullyRegistred()) throw Error("/", t._("You already have a password"));
function doDefinePassword(?key:String, ?u:db.User) {
if (app.user.isFullyRegistred())
throw Error("/", t._("You already have a password"));
var form = new Form("definepass");
var pass1 = new StringInput("pass1", t._("Your new password"));
@@ -211,16 +219,13 @@ class User extends Controller
form.addElement(pass2);
if (form.isValid()) {
if ( form.getValueOf("pass1") == form.getValueOf("pass2")) {
if (form.getValueOf("pass1") == form.getValueOf("pass2")) {
app.user.lock();
app.user.setPass(form.getValueOf("pass1"));
app.user.update();
throw Ok('/', t._("Congratulations, your account is now protected by a password."));
}else {
form.addError( t._("You must key-in two times the same password"));
} else {
form.addError(t._("You must key-in two times the same password"));
}
}
view.form = form;
@@ -231,25 +236,20 @@ class User extends Controller
* landing page when coming from an invitation
* @param k
*/
public function doValidate(k:String ) {
public function doValidate(k:String) {
var uid = Std.parseInt(sugoi.db.Cache.get("validation" + k));
if (uid == null || uid==0) throw Error('/user/login', t._("Your invitation is invalid or expired ($k)"));
if (uid == null || uid == 0)
throw Error('/user/login', t._("Your invitation is invalid or expired ($k)"));
var user = db.User.manager.get(uid, true);
db.User.login(user, user.email);
var groups = user.getAmaps();
if(groups.length>0) app.session.data.amapId = groups.first().id;
if (groups.length > 0)
app.session.data.amapId = groups.first().id;
sugoi.db.Cache.destroy("validation" + k);
throw Ok("/user/definePassword", t._("Congratulations ::userName::, your account is validated!", {userName:user.getName()}));
throw Ok("/user/definePassword", t._("Congratulations ::userName::, your account is validated!", {userName: user.getName()}));
}
}
+66 -97
View File
@@ -1,19 +1,18 @@
package controller.admin;
import haxe.web.Dispatch;
import Common;
class Admin extends Controller {
public function new() {
super();
view.category = 'admin';
//trigger a "Nav" event
// trigger a "Nav" event
var nav = new Array<Link>();
var e = Nav(nav,"admin");
var e = Nav(nav, "admin");
app.event(e);
view.nav = e.getParameters()[0];
}
@tpl("admin/default.mtt")
@@ -24,44 +23,36 @@ class Admin extends Controller {
@tpl("admin/emails.mtt")
function doEmails() {
var browse = function(index:Int, limit:Int) {
return sugoi.db.BufferedMail.manager.search($sdate==null,{limit:[index,limit],orderBy:-cdate},false);
return sugoi.db.BufferedMail.manager.search($sdate == null, {limit: [index, limit], orderBy: -cdate}, false);
}
var count = sugoi.db.BufferedMail.manager.count($sdate==null);
view.browser = new sugoi.tools.ResultsBrowser(count,10,browse);
var count = sugoi.db.BufferedMail.manager.count($sdate == null);
view.browser = new sugoi.tools.ResultsBrowser(count, 10, browse);
view.num = count;
}
@tpl("form.mtt")
function doSmtp() {
var f = new sugoi.form.Form("emails");
var data = [
{label:"SMTP",value:"smtp"},
{label:"Mandrill API",value:"mandrill"},
];
var data = [{label: "SMTP", value: "smtp"}, {label: "Mandrill API", value: "mandrill"},];
var mailer = sugoi.db.Variable.get("mailer")==null ? "smtp" : sugoi.db.Variable.get("mailer");
var host = sugoi.db.Variable.get("smtp_host")==null ? App.config.get("smtp_host") : sugoi.db.Variable.get("smtp_host");
var port = sugoi.db.Variable.get("smtp_port")==null ? App.config.get("smtp_port") : sugoi.db.Variable.get("smtp_port");
var user = sugoi.db.Variable.get("smtp_user")==null ? App.config.get("smtp_user") : sugoi.db.Variable.get("smtp_user");
var pass = sugoi.db.Variable.get("smtp_pass")==null ? App.config.get("smtp_pass") : sugoi.db.Variable.get("smtp_pass");
var mailer = sugoi.db.Variable.get("mailer") == null ? "smtp" : sugoi.db.Variable.get("mailer");
var host = sugoi.db.Variable.get("smtp_host") == null ? "<SMTP_SERVER>" : sugoi.db.Variable.get("smtp_host");
var port = sugoi.db.Variable.get("smtp_port") == null ? "587" : sugoi.db.Variable.get("smtp_port");
var user = sugoi.db.Variable.get("smtp_user") == null ? "" : sugoi.db.Variable.get("smtp_user");
var pass = sugoi.db.Variable.get("smtp_pass") == null ? "" : sugoi.db.Variable.get("smtp_pass");
f.addElement(new sugoi.form.elements.StringSelect("mailer", "Mailer", data, mailer ));
f.addElement(new sugoi.form.elements.StringSelect("mailer", "Mailer", data, mailer));
f.addElement(new sugoi.form.elements.StringInput("smtp_host", "host", host));
f.addElement(new sugoi.form.elements.StringInput("smtp_port", "port", port));
f.addElement(new sugoi.form.elements.StringInput("smtp_user", "user", user));
f.addElement(new sugoi.form.elements.StringInput("smtp_pass", "pass", pass));
if (f.isValid()){
for ( k in ["mailer","smtp_host","smtp_port","smtp_user","smtp_pass"]){
if (f.isValid()) {
for (k in ["mailer", "smtp_host", "smtp_port", "smtp_user", "smtp_pass"]) {
sugoi.db.Variable.set(k, f.getValueOf(k));
}
throw Ok("/admin/emails", t._("Configuration updated") );
throw Ok("/admin/emails", t._("Configuration updated"));
}
view.title = t._("Email service configuration");
@@ -72,67 +63,60 @@ class Admin extends Controller {
d.dispatch(new controller.admin.Plugins());
}
@tpl("admin/taxo.mtt")
function doTaxo(){
function doTaxo() {
view.categ = db.TxpCategory.manager.all();
}
/**
* Display errors logged in DB
*/
@tpl("admin/errors.mtt")
function doErrors( args:{?user: Int, ?like: String, ?empty:Bool} ) {
function doErrors(args:{?user:Int, ?like:String, ?empty:Bool}) {
view.now = Date.now();
view.u = args.user!=null ? db.User.manager.get(args.user,false) : null;
view.like = args.like!=null ? args.like : "";
view.u = args.user != null ? db.User.manager.get(args.user, false) : null;
view.like = args.like != null ? args.like : "";
var sql = "";
if( args.user!=null ) sql += " AND uid="+args.user;
//if( args.like!=null && args.like != "" ) sql += " AND error like "+sys.db.Manager.cnx.quote("%"+args.like+"%");
if (args.user != null)
sql += " AND uid=" + args.user;
// if( args.like!=null && args.like != "" ) sql += " AND error like "+sys.db.Manager.cnx.quote("%"+args.like+"%");
if (args.empty) {
sys.db.Manager.cnx.request("truncate table Error");
}
var errorsStats = sys.db.Manager.cnx.request("select count(id) as c, DATE_FORMAT(date,'%y-%m-%d') as day from Error where date > NOW()- INTERVAL 1 MONTH "+sql+" group by day order by day").results();
var errorsStats = sys.db.Manager.cnx.request("select count(id) as c, DATE_FORMAT(date,'%y-%m-%d') as day from Error where date > NOW()- INTERVAL 1 MONTH "
+ sql
+ " group by day order by day")
.results();
view.errorsStats = errorsStats;
view.browser = new sugoi.tools.ResultsBrowser(
sugoi.db.Error.manager.unsafeCount("SELECT count(*) FROM Error WHERE 1 "+sql),
20,
function(start, limit) { return sugoi.db.Error.manager.unsafeObjects("SELECT * FROM Error WHERE 1 "+sql+" ORDER BY date DESC LIMIT "+start+","+limit,false); }
);
view.browser = new sugoi.tools.ResultsBrowser(sugoi.db.Error.manager.unsafeCount("SELECT count(*) FROM Error WHERE 1 " + sql), 20,
function(start, limit) {
return sugoi.db.Error.manager.unsafeObjects("SELECT * FROM Error WHERE 1 " + sql + " ORDER BY date DESC LIMIT " + start + "," + limit, false);
});
}
@tpl("admin/graph.mtt")
function doGraph(?key:String,?year:Int,?month:Int){
function doGraph(?key:String, ?year:Int, ?month:Int) {
var from = new Date(year, month, 1, 0, 0, 0);
var to = new Date(year, month + 1, 0, 23, 59, 59);
var from = new Date(year,month,1,0,0,0);
var to = new Date(year,month+1,0,23,59,59);
if(app.params.exists("recompute")){
switch(key){
if (app.params.exists("recompute")) {
switch (key) {
case "basket":
for( d in 1...to.getDate()){
var _from = new Date(year,month,d,0,0,0);
var _to = new Date(year,month,d,23,59,59);
var value = db.Basket.manager.count($cdate>=_from && $cdate<=_to);
var g = db.Graph.record(key,value, _from );
for (d in 1...to.getDate()) {
var _from = new Date(year, month, d, 0, 0, 0);
var _to = new Date(year, month, d, 23, 59, 59);
var value = db.Basket.manager.count($cdate >= _from && $cdate <= _to);
var g = db.Graph.record(key, value, _from);
// trace(value,_from,g);
}
}
}
}
}
var data = db.Graph.getRange(key,from,to);
var data = db.Graph.getRange(key, from, to);
view.data = data;
view.from = from;
view.to = to;
@@ -140,55 +124,46 @@ class Admin extends Controller {
var averageValue = 0.0;
var total = 0.0;
for( d in data) total += d.value;
averageValue = total/data.length;
for (d in data)
total += d.value;
averageValue = total / data.length;
view.total = total;
view.averageValue = averageValue;
}
function doFixDistribValidation() {
Sys.println("===== Liste des distributions ayant été re-validées ====<br>");
//Get the current group
// Get the current group
var group = app.user.amap;
//Get all the contracts for this given group
var contractIds = Lambda.map(group.getContracts(),function(x) return x.id);
//Get all the validated distributions for this given group
var validatedDistribs = db.Distribution.manager.search( ($contractId in contractIds) && $validated == true, {orderBy:date}, false);
for (distrib in validatedDistribs){
// Get all the contracts for this given group
var contractIds = Lambda.map(group.getContracts(), function(x) return x.id);
// Get all the validated distributions for this given group
var validatedDistribs = db.Distribution.manager.search(($contractId in contractIds) && $validated == true, {orderBy: date}, false);
for (distrib in validatedDistribs) {
service.PaymentService.validateDistribution(distrib);
Sys.println(distrib.toString() + "<br>");
}
Sys.println("===== Fin de la liste ====");
}
function doCheckDistribValidation() {
Sys.println("===== Liste des distributions validées ayant des opérations/paiements non validés ====<br>");
//Get the current group
// Get the current group
var group = app.user.amap;
//Get all the contracts for this given group
var contractIds = Lambda.map(group.getContracts(),function(x) return x.id);
//Get all the validated distributions for this given group
var validatedDistribs = db.Distribution.manager.search( ($contractId in contractIds) && $validated == true, {orderBy:date}, false);
for (distrib in validatedDistribs){
for (user in distrib.getUsers()){
// Get all the contracts for this given group
var contractIds = Lambda.map(group.getContracts(), function(x) return x.id);
// Get all the validated distributions for this given group
var validatedDistribs = db.Distribution.manager.search(($contractId in contractIds) && $validated == true, {orderBy: date}, false);
for (distrib in validatedDistribs) {
for (user in distrib.getUsers()) {
var basket = db.Basket.get(user, distrib.place, distrib.date);
if (basket == null || basket.isValidated()) continue;
if (basket == null || basket.isValidated())
continue;
for (order in basket.getOrders()){
for (order in basket.getOrders()) {
if (!order.paid) {
Sys.println(order.distribution.toString() + "<br>");
Sys.println(order.toString() + "<br>");
@@ -196,28 +171,22 @@ class Admin extends Controller {
}
var operation = basket.getOrderOperation(false);
if (operation != null){
if (operation != null) {
if (operation.pending) {
Sys.println(distrib.toString() + "<br>");
Sys.println(operation.toString() + "<br>");
}
for ( payment in basket.getPayments()){
if (payment.pending){
for (payment in basket.getPayments()) {
if (payment.pending) {
Sys.println(distrib.toString() + "<br>");
Sys.println(payment.toString() + "<br>");
}
}
}
}
}
Sys.println("===== Fin de la liste ====");
}
}
+14 -21
View File
@@ -1,38 +1,34 @@
package form;
import sugoi.form.elements.RadioGroup;
import Common;
class ColorRadioGroup extends RadioGroup
{
public function new(name:String, label:String,selected:String)
{
class ColorRadioGroup extends RadioGroup {
public function new(name:String, label:String, selected:String) {
var data = [];
var i = 0;
for (c in db.CategoryGroup.COLORS) {
data.push( { value:Std.string(c), label:Std.string(i) } );
data.push({value: Std.string(c), label: Std.string(i)});
i++;
}
super(name, label, data, selected, "1", false, true);
}
override public function render():String
{
override public function render():String {
var s = "";
var n = parentForm.name + "_" +name;
var n = parentForm.name + "_" + name;
var c = 0;
if (data != null)
{
for (row in data)
{
if (data != null) {
for (row in data) {
var radio = "<input type=\"radio\" name=\"" + n + "\" id=\"" + n + c + "\" value=\"" + row.label + "\" "
+ (row.label == Std.string(value) ? "checked" : "") + " />\n";
var img = "<div style='margin-right:16px;width:32px;height:32px;background:"
+ App.current.view.intToHex(Std.parseInt(row.value))
+ ";'></div>";
var radio = "<input type=\"radio\" name=\""+n+"\" id=\""+n+c+"\" value=\"" + row.label + "\" " + (row.label == Std.string(value) ? "checked":"") +" />\n";
var img = "<div style='margin-right:16px;width:32px;height:32px;background:"+App.current.view.intToHex(Std.parseInt(row.value))+";'></div>";
s += "<label for=\"" + n+c + "\" class='checkbox' style='display: inline-block;'>"+radio + " "+img+" </label>";
s += "<label for=\"" + n + c + "\" class='checkbox' style='display: inline-block;'>" + radio + " " + img + " </label>";
c++;
}
@@ -40,7 +36,4 @@ class ColorRadioGroup extends RadioGroup
return s;
}
}
+2
View File
@@ -13,6 +13,8 @@ class WaitingListService{
var w = new db.WaitingList();
w.user = user;
w.group = group;
if (message == null ) message = "";
//message = "souscription = " + message;
w.message = message;
w.insert();
+135 -126
View File
@@ -1,25 +1,25 @@
package sugoi;
import sugoi.i18n.TemplateTranslator;
import sugoi.Web;
class BaseApp {
public var cnx:sys.db.Connection;
public var template:templo.Loader;
public var maintain:Bool;
public var session:sugoi.db.Session;
public var view:View;
public var user:db.User;
public var params:Map<String, String>;
public var cookieName:String;
public var cookieDomain:String;
public var uri:String;
public var cnx : sys.db.Connection;
public var template : templo.Loader;
public var maintain : Bool;
public var session : sugoi.db.Session;
public var view : View;
public var user : db.User;
public var params : Map<String,String>;
public var cookieName : String;
public var cookieDomain : String;
public var uri : String;
public static var config:Config;
public static var config: Config;
//public static var classPathes = sugoi.tools.Macros.getClassPathes();
// public static var classPathes = sugoi.tools.Macros.getClassPathes();
public function new() {
if (config == null) {
loadConfig();
}
@@ -28,24 +28,32 @@ class BaseApp {
cookieDomain = "." + App.config.HOST;
#if plugins
if( false ) sugoi.plugin.PlugIn.copyTpl();
if (false)
sugoi.plugin.PlugIn.copyTpl();
#end
// This macro generates translated templates for each langage
#if i18n_generation
if( false ) TemplateTranslator.parse("lang/master");
if (false)
TemplateTranslator.parse("lang/master");
#end
}
public function loadConfig() {
App.config = BaseApp.config = new sugoi.Config();
var PATH = Web.getCwd() + "../";
var json = haxe.Json.parse(sys.io.File.getContent(PATH + "package.json"));
App.VERSION = json.version;
App.log('configuration has been reloaded, VERSION=${App.VERSION}');
}
public function loadTemplate( t : String ) {
public function loadTemplate(t:String) {
templo.Loader.OPTIMIZED = App.config.DEBUG == false;
templo.Loader.BASE_DIR = App.config.TPL;
templo.Loader.TMP_DIR = App.config.TPL_TMP;
if ( t == null ) return null;
if (t == null)
return null;
#if neko
return new templo.Loader(t, App.config.getBool("cachetpl"));
#else
@@ -53,39 +61,39 @@ class BaseApp {
#end
}
public function setTemplate( t : String ) {
public function setTemplate(t:String) {
template = t == null ? null : loadTemplate(t);
}
public function initLang( lang : String ) {
public function initLang(lang:String) {
if (lang == null || lang == "")
lang = config.LANG;
if (lang == null || lang == "") lang = config.LANG;
//Define template path
// Define template path
var path;
if (!App.config.DEBUG){
if (!App.config.DEBUG) {
path = Web.getCwd() + "../lang/" + lang + "/";
}else{
} else {
path = Web.getCwd() + "../lang/master/";
}
App.config.TPL = path + "tpl/";
App.config.TPL_TMP = path + "tmp/";
//init system locale
if ( !Sys.setTimeLocale("en_US.UTF-8") ) {
// init system locale
if (!Sys.setTimeLocale("en_US.UTF-8")) {
Sys.setTimeLocale("en");
}
//init gettext translator
// init gettext translator
sugoi.i18n.Locale.init(lang);
return true;
}
function saveAndClose() {
if( cnx == null ) return;
if( session.sid != null )
if (cnx == null)
return;
if (session.sid != null)
session.update();
cnx.commit();
@@ -94,26 +102,28 @@ class BaseApp {
untyped cnx.request = function(s) return null;
}
function executeTemplate( ?save ) {
function executeTemplate(?save) {
view.init();
var result = template.execute(view);
if ( save ) saveAndClose();
if (save)
saveAndClose();
#if php
//strange bug with templo in PHP
if (result.substr(0, 4) == "null") result = result.substr(4);
// strange bug with templo in PHP
if (result.substr(0, 4) == "null")
result = result.substr(4);
#end
Sys.print(result);
}
function onMeta( m : String, args : Array<Dynamic> ) {
switch( m ) {
function onMeta(m:String, args:Array<Dynamic>) {
switch (m) {
case "tpl":
setTemplate(args[0]);
case "logged":
if ( user == null )
throw sugoi.ControllerAction.RedirectAction("/?__redirect="+Web.getURI());
if (user == null)
throw sugoi.ControllerAction.RedirectAction("/?__redirect=" + Web.getURI());
case "admin":
if( user == null || !user.isAdmin() )
if (user == null || !user.isAdmin())
throw sugoi.ControllerAction.RedirectAction("/");
default:
}
@@ -124,111 +134,109 @@ class BaseApp {
*/
function detectLang() {
var l = Web.getClientHeader("Accept-Language");
if( l != null )
for( l in l.split(",") ) {
if (l != null)
for (l in l.split(",")) {
l = l.split(";")[0];
l = l.split("-")[0];
l = StringTools.trim(l);
for( a in App.config.LANGS )
if( a == l )
for (a in App.config.LANGS)
if (a == l)
return a;
}
return App.config.LANG;
}
/**
* Setup current app language
*/
function setupLang() {
// this app is monolingual and doesn't manage i18n
if (App.config.LANG == "master")
return;
//this app is monolingual and doesn't manage i18n
if (App.config.LANG == "master") return;
//lang is taken from user object or from HTTP headers
if ( session.lang == null || !Lambda.has(App.config.LANGS, session.lang) ){
// lang is taken from user object or from HTTP headers
if (session.lang == null || !Lambda.has(App.config.LANGS, session.lang)) {
session.lang = (user == null) ? detectLang() : user.lang;
}
//override if param is given
// override if param is given
var lang = params.get("lang");
if ( lang != null && Lambda.has(App.config.LANGS, lang) ){
if (lang != null && Lambda.has(App.config.LANGS, lang)) {
session.lang = lang;
}
//init lang
// init lang
initLang(session.lang);
}
/**
* Get current application langage (2 letters lowercase)
*/
public function getLang(){
public function getLang() {
return (session != null && session.lang != null && session.lang != "") ? session.lang : App.config.LANG;
}
public function rollback() {
if( cnx != null ) cnx.rollback();
if (cnx != null)
cnx.rollback();
sys.db.Manager.cleanup();
if( user != null && session != null )
if (user != null && session != null)
user = session.user;
// does not reset session
}
public function setCookie( oldCookie : String ){
if( session != null && session.sid != null && session.sid != oldCookie ) {
Web.setHeader("Set-Cookie", cookieName+"=" + session.sid + "; path=/;");
public function setCookie(oldCookie:String) {
if (session != null && session.sid != null && session.sid != oldCookie) {
Web.setHeader("Set-Cookie", cookieName + "=" + session.sid + "; path=/;");
}
}
function mainLoop() {
params = Web.getParams();
//Get session
// Get session
var sids = [];
var cookieSid = Web.getCookies().get(cookieName);
if( params.exists("sid") ) sids.push(params.get("sid"));
if( cookieSid != null ) sids.push(cookieSid);
if (params.exists("sid"))
sids.push(params.get("sid"));
if (cookieSid != null)
sids.push(cookieSid);
session = sugoi.db.Session.init(sids);
//Check for maintenance
// Check for maintenance
maintain = sugoi.db.Variable.getInt("maintain") != 0;
user = session.user;
//setup langage
// setup langage
setupLang();
if( maintain && ((user != null && user.isAdmin()) ) )
if (maintain && ((user != null && user.isAdmin())))
maintain = false;
setCookie(cookieSid);
if( maintain ) {
if (maintain) {
setTemplate("maintain.mtt");
executeTemplate();
return;
}
//dispatching
// dispatching
try {
uri = Web.getURI();
if ( StringTools.endsWith(uri, "/index.n") ) uri = uri.substr(0, -8);
if (StringTools.endsWith(uri, "/index.n"))
uri = uri.substr(0, -8);
//"before dispatch" callback
// "before dispatch" callback
beforeDispatch();
var d = new haxe.web.Dispatch(uri, params);
d.onMeta = onMeta;
d.dispatch(new controller.Main());
} catch ( e : haxe.web.Dispatch.DispatchError ) {
//dispatch / routing error
if ( App.config.DEBUG ) {
} catch (e:haxe.web.Dispatch.DispatchError) {
// dispatch / routing error
if (App.config.DEBUG) {
#if neko
neko.Lib.rethrow(e);
#else
@@ -238,32 +246,34 @@ class BaseApp {
cnx.rollback();
Web.redirect("/");
return;
} catch ( e : sugoi.ControllerAction) {
switch( e ) {
} catch (e:sugoi.ControllerAction) {
switch (e) {
case RedirectAction(url):
Web.redirect(url);
template = null;
case ErrorAction(url, text), OkAction(url,text):
if( text == null ) {
case ErrorAction(url, text), OkAction(url, text):
if (text == null) {
text = url;
url = Web.getURI();
}
Web.redirect(url);
var error = switch(e) { case ErrorAction(_): true; default: false; };
if( error ) rollback();
if ( error ) {
session.addMessage(text,true);
}else {
var error = switch (e) {
case ErrorAction(_): true;
default: false;
};
if (error)
rollback();
if (error) {
session.addMessage(text, true);
} else {
session.addMessage(text);
}
template = null;
}
}
//Render template
if ( template == null ) {
// Render template
if (template == null) {
saveAndClose();
} else {
executeTemplate(true); // will saveAndClose
@@ -274,12 +284,10 @@ class BaseApp {
* Override this function if you want
* to insert some actions
*/
public function beforeDispatch() {
public function beforeDispatch() {}
}
public function logError( e : Dynamic, ?stack : String ) {
var stack = if( stack != null ) stack else haxe.CallStack.toString(haxe.CallStack.exceptionStack());
public function logError(e:Dynamic, ?stack:String) {
var stack = if (stack != null) stack else haxe.CallStack.toString(haxe.CallStack.exceptionStack());
var message = new StringBuf();
message.add(Std.string(e));
message.add("\n");
@@ -288,43 +296,42 @@ class BaseApp {
var e = new sugoi.db.Error();
e.url = Web.getURI();
e.ip = Web.getClientIP();
e.user = if( user != null ) user else null;
e.user = if (user != null) user else null;
e.date = Date.now();
e.userAgent = Web.getClientHeader("User-Agent");
e.error = message.toString();
e.insert();
}
function errorHandler( e:Dynamic ) {
function errorHandler(e:Dynamic) {
try {
var stack = haxe.CallStack.toString(haxe.CallStack.exceptionStack());
// ROLLBACK and LOG
if ( cnx != null ) {
if (cnx != null) {
cnx.rollback();
logError(e,stack);
logError(e, stack);
}
//log also in a file, in case we don't have a valid connexion to DB
Web.logMessage(e+"\n" + stack);
// log also in a file, in case we don't have a valid connexion to DB
Web.logMessage(e + "\n" + stack);
maintain = true;
view = new View();
view.message = Std.string(e);
if ( App.config.DEBUG || (user != null && user.isAdmin()) ) {
if (App.config.DEBUG || (user != null && user.isAdmin())) {
view.stack = stack;
}
setTemplate("error.mtt");
executeTemplate(false);
} catch( e : Dynamic ) {
} catch (e:Dynamic) {
Sys.print("<pre>");
Sys.println("Error : "+try Std.string(e) catch( e : Dynamic ) "???");
Sys.println("Error : " + try Std.string(e) catch (e:Dynamic) "???");
Sys.println(haxe.CallStack.toString(haxe.CallStack.exceptionStack()));
try {
if( cnx != null )
sugoi.db.Error.manager.get(0,false);
} catch( e : Dynamic ) {
if (cnx != null)
sugoi.db.Error.manager.get(0, false);
} catch (e:Dynamic) {
Sys.println("Initializing Database...");
sys.db.Admin.initializeDatabase();
Sys.println("Done");
@@ -339,7 +346,7 @@ class BaseApp {
*/
function init() {
maintain = App.config.getBool("maintain");
if( maintain ) {
if (maintain) {
view = new View();
setTemplate("maintain.mtt");
executeTemplate(false);
@@ -348,23 +355,23 @@ class BaseApp {
try {
var dbstr = App.config.get("database");
var dbreg = ~/([^:]+):\/\/([^:]+):([^@]*?)@([^:]+)(:[0-9]+)?\/(.*?)$/;
if( !dbreg.match(dbstr) )
if (!dbreg.match(dbstr))
throw "Configuration requires a valid database attribute, format is : mysql://user:password@host:port/dbname";
var port = dbreg.matched(5);
var dbparams = {
user:dbreg.matched(2),
pass:dbreg.matched(3),
host:dbreg.matched(4),
port:port == null ? 3306 : Std.parseInt(port.substr(1)),
database:dbreg.matched(6),
socket:null
user: dbreg.matched(2),
pass: dbreg.matched(3),
host: dbreg.matched(4),
port: port == null ? 3306 : Std.parseInt(port.substr(1)),
database: dbreg.matched(6),
socket: null
};
cnx = sys.db.Mysql.connect(dbparams);
} catch( e : Dynamic ) {
} catch (e:Dynamic) {
errorHandler(e);
return false;
}
if( App.config.SQL_LOG )
if (App.config.SQL_LOG)
cnx = new sugoi.tools.DebugConnection(cnx);
return true;
}
@@ -372,7 +379,7 @@ class BaseApp {
function cloneApp() {
// ensure that we have no variable initialized in app loop
var app = new App();
var bapp : BaseApp = app;
var bapp:BaseApp = app;
bapp.cnx = cnx;
bapp.view = new View();
App.current = app;
@@ -380,13 +387,15 @@ class BaseApp {
}
function run() {
// Will close the connection
sys.db.Transaction.main(cnx, cloneApp, function(e) { var b : BaseApp = App.current; b.errorHandler(e); });
sys.db.Transaction.main(cnx, cloneApp, function(e) {
var b:BaseApp = App.current;
b.errorHandler(e);
});
App.current = null;
}
function sendHeaders(){
function sendHeaders() {
Web.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
Web.setHeader("Pragma", "no-cache");
Web.setHeader("Expires", "-1");
@@ -396,28 +405,28 @@ class BaseApp {
}
static function main() {
/**
* this macro will parse the code and generate the allTexts.pot file
* which will be used as a template for translation files (*.po and *.mo)
*/
#if i18n_parsing
if( false ) sugoi.i18n.GetText.parse(["src", "lang/master","js","common"], "www/lang/allTexts.pot");
if (false)
sugoi.i18n.GetText.parse(["src", "lang/master", "js", "common"], "www/lang/allTexts.pot");
#end
App.current = new App();
var a : BaseApp = App.current;
var a:BaseApp = App.current;
a.sendHeaders();
if( !a.init() ) {
if (!a.init()) {
a = null;
return;
}
a.run();
a = null;
#if neko
if ( App.config.getInt("cache", 0) == 1 ) {
if (App.config.getInt("cache", 0) == 1) {
neko.Web.cacheModule(App.main);
}
#end
+2
View File
@@ -20,12 +20,14 @@ class BaseView implements Dynamic {
this.HOST = App.config.HOST;
this.DATA_HOST = App.config.DATA_HOST;
this.DEBUG = App.config.DEBUG;
this.BANDEAU_REGION = App.config.BANDEAU_REGION;
this.NAME = App.config.NAME;
this.isAdmin = app.user != null && app.user.isAdmin();
//Access basic functions in views
this.Std = Std;
this.Math = Math;
this.Config = App.config;
if ( App.config.SQL_LOG ) {
+34 -33
View File
@@ -3,61 +3,62 @@ package sugoi;
import sugoi.Web;
class Config {
public var PATH :String;
//public var json : Dynamic;
public var xml : Xml;
public var LANG :String;
public var LANGS :Array<String>;
public var TPL :String;
public var TPL_TMP :String;
public var DEBUG :Bool;
public var HOST :String;
public var NAME :String;
public var KEY :String;
public var DATA_HOST :String;
public var SQL_LOG :Bool;
public var PATH:String;
// public var json : Dynamic;
public var xml:Xml;
public var LANG:String;
public var LANGS:Array<String>;
public var TPL:String;
public var TPL_TMP:String;
public var DEBUG:Bool;
public var BANDEAU_REGION:Bool;
public var HOST:String;
public var NAME:String;
public var KEY:String;
public var DATA_HOST:String;
public var SQL_LOG:Bool;
public function new(?path:String) {
PATH = (path != null) ? path : Web.getCwd() + "../";
//json = haxe.Json.parse(sys.io.File.getContent(PATH + "config.json"));
xml = Xml.parse(sys.io.File.getContent(PATH + "config.xml")).firstElement();
LANG = get("lang");
LANGS = get("langs").split(";");
NAME = get("name", "cagettepei");
LANG = get("lang", "fr");
LANGS = get("langs", "fr").split(";");
TPL = PATH + "lang/" + LANG + "/tpl/";
TPL_TMP = PATH + "lang/" + LANG + "/tmp/";
DEBUG = get("debug","0") == "1";
DEBUG = get("debug", "0") == "1";
BANDEAU_REGION = get("bandeau_region", "0") == "1";
HOST = get("host");
NAME = get("name");
KEY = get("key");
DATA_HOST = get("dataHost","data."+HOST);
DATA_HOST = get("dataHost", "data." + HOST);
SQL_LOG = getBool("sqllog", false);
}
public function defined( val : String ) {
//return Reflect.field(xml,val) != null;
public function defined(val:String) {
// return Reflect.field(xml,val) != null;
return xml.get(val) != null;
}
public function getBool( val : String, ?def ) {
public function getBool(val:String, ?def) {
var v = get(val);
if( v == null ) return def;
return( v == "1" || v == "true" );
if (v == null)
return def;
return (v == "1" || v == "true");
}
public function get( val : String, ?def : String ) : String {
//var v = Reflect.field(xml,val);
public function get(val:String, ?def:String):String {
// var v = Reflect.field(xml,val);
var v = xml.get(val);
if( v == null )
if (v == null)
v = def;
if( v == null )
throw "Missing config attribute : '"+val+"'";
if (v == null)
throw "Missing config attribute : '" + val + "'";
return v;
}
public function getInt( val : String, ?def : Int ) : Int {
return Std.parseInt(get(val,Std.string(def)));
public function getInt(val:String, ?def:Int):Int {
return Std.parseInt(get(val, Std.string(def)));
}
}
+2 -2
View File
@@ -32,8 +32,8 @@ class Mail implements IMail {
public function setSender(email, ?name, ?userId) {
if (!isValid(email))
throw "invalid sender email : \"" + email + "\"";
sender = {name: name, email: email, userId: userId};
var finalName = (name != null) ? thx.text.Diactrics.clean(name) : null;
sender = {name: finalName, email: email, userId: userId};
return this;
}
+395 -444
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
ErrorDocument 404 /index.n
Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

+5 -4
View File
@@ -14,6 +14,7 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Poedit 2.0.6\n"
#: src/payment/Cash.hx:294
msgid "Cash"
msgstr "Espèces / Carte Bancaire"
@@ -1538,7 +1539,7 @@ msgid ""
"Group and user 'admin' created. Your email is 'admin@cagette.net' and your "
"password is 'admin'"
msgstr ""
"Groupe et utilisateur 'admin' créé. Votre email est 'admin@cagette.net' et "
"Groupe et utilisateur 'admin' créé. Votre email est 'admin@cagettepei.re' et "
"votre mot de passe est 'admin'"
#: src/controller/Install.hx:4677
@@ -2237,7 +2238,7 @@ msgid ""
"Welcome in the group of ::name::!\n"
" You can look at the delivery planning or make a new order."
msgstr ""
"Bienvenue sur la cagette de ::name:: !\n"
"Bienvenue sur le CagettePéi de ::name:: !\n"
" Vous pouvez consulter votre planning de distribution ou faire une nouvelle "
"commande."
@@ -4551,7 +4552,7 @@ msgstr "Extrait non exhaustif des produits proposés :"
#: lang/master/tpl/group/view.mtt:5027
msgid "http://www.cagette.net"
msgstr "http://www.cagette.net"
msgstr "https://git.artcode.re/cagetters/cagettepei"
#: lang/master/tpl/group/view.mtt:5060
msgid "Cagette.net, the free software of food direct-selling"
@@ -4618,7 +4619,7 @@ msgid ""
"Cagette.net is made by <a href='https://www.alilo.fr' target='_blank'><img "
"src='/img/alilo-trans-black.png' /></a>"
msgstr ""
"CagettePéi est une fourche du logiciel Cagette.net réalisé par <a href='https://www.alilo.fr' "
"CagettePéi est un logiciel libre, fourche du logiciel Cagette "
"target='_blank'><img src='/img/alilo-trans-black.png' /></a>"
#: lang/master/tpl/validate/user.mtt:2124