Compare commits

...
53 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
30 changed files with 1499 additions and 1365 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.11.0
1.16.0
+7 -6
View File
@@ -20,7 +20,7 @@ install_dev:
#set config file to debug=1
#@sed -e 's?debug=.*?debug="1"?g' --in-place config.xml
#install haxe dependencies in .haxelib
haxelib newrepo
haxelib newrepo
haxelib -always install cagette.hxml
haxelib -always install cagetteJs.hxml
#template tools
@@ -47,7 +47,7 @@ compile:
echo "compile CagettePéi core"; \
haxe cagette.hxml; \
fi
#compile SASS files to CSS
css:
@@ -64,17 +64,18 @@ frontend:
chown www-data:www-data tmp
#update POT file from source
i18n:
i18n:
haxe potGeneration.hxml
#compile templates in each language, required for production env.
templates:
templates:
mkdir -p lang/master/tmp
haxe cagette.hxml -D i18n_generation
@make LANG=fr ctemplates
msgfmt www/lang/texts_fr.po -o www/lang/texts_fr.mo
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"
+12 -2
View File
@@ -4,11 +4,21 @@
default_email = "<EMAIL>"
webmaster_email = "<EMAIL>"
key = "<SECRET_PHRASE>"
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>"
/>
+101 -97
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 );
ReactDOM.render(jsx('<$VATBox ttc="$ttcprice" currency="$currency" vatRates="$rates" vat="$vat" formName="$formName"/>'), input.parentElement);
//remove(input);
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);
}
/*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(){
ReactDOM.render(jsx('<$ReportHeader />'), js.Browser.document.querySelector('div.reportHeaderContainer'));
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.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);
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);
}
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,52 +166,65 @@ 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;
}
public function shop(place:Int, date:String) {
ReactDOM.render(jsx('<$Store date=$date place=$place/>'), js.Browser.document.querySelector('#shop'));
ReactDOM.render(jsx('<$Store date=$date place=$place/>'), js.Browser.document.querySelector('#shop'));
}
public function groupMap(lat:String,lng:String,address:String) {
ReactDOM.render(jsx('<$GroupMapRoot lat="$lat" lng="$lng" address="$address"/>'), js.Browser.document.querySelector('#map'));
public function groupMap(lat:String, lng:String, address:String) {
ReactDOM.render(jsx('<$GroupMapRoot lat="$lat" lng="$lng" address="$address"/>'), js.Browser.document.querySelector('#map'));
}
/**
* 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();
}
}
+33 -79
View File
@@ -1,5 +1,5 @@
::use 'base.mtt'::
::if getParam('__redirect')!=null::
<!-- need to login to go to this page-->
<script>$(function(){
@@ -16,11 +16,11 @@
<h1>::_("Cagette.net")::</h1>
::end::
</div>
<div class="col-md-4 accountBlock">
::if user != null::
<div class="col-md-4 accountBlock">
::if user != null::
<div class="dropdown pull-right text-right userName" style="margin-top:16px;">
<a class="" style="margin-right:16px;" href="/user/choose?show=1">
<span class="glyphicon glyphicon-chevron-left"></span>::_("Change group")::
</a>
@@ -29,46 +29,46 @@
<span class="glyphicon glyphicon-user"></span>
::user.getName()::
::if user.firstName2!=null::
::_("et"):: ::user.lastName2:: ::user.firstName2::
::_("et"):: ::user.lastName2:: ::user.firstName2::
::end::
</a>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1">
<li><a href="/user/logout"><span class="glyphicon glyphicon-log-out"></span> ::_("Log out")::</a></li>
</ul>
</div>
</div>
::else::
<div class="pull-right text-right">
<a href="/user/login" class="btn btn-default btn-sm"><span class="glyphicon glyphicon-user"></span> ::_("Log in")::</a>
<a class="btn btn-default btn-sm" href="/group/map"><span class="glyphicon glyphicon-search"></span> ::_("Look for another group")::</a>
<a class="btn btn-default btn-sm" href="/group/map"><span class="glyphicon glyphicon-search"></span> ::_("Look for another group")::</a>
</div>
::end::
</div>
</div>
</div>
::if user != null && noGroup!=true::
<nav class="navbar navbar-default" ::cond user.getAmap()!=null::>
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#cagette-navbar">
<span class="sr-only">Toggle navigation</span>
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
</button>
</div>
<div class="collapse navbar-collapse" id="cagette-navbar">
<ul class="nav navbar-nav navbar-left">
<li ::attr class if(category=="home") 'active' ::><a href="/">::_("Home")::</a></li>
<li ::attr class if(category=="contract" ) 'active' ::><a href="/contract">::_("My account")::</a></li>
<li ::attr class if(category=="amap") 'active' ::><a href="/amap">::_("Farmers")::</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li id="member" ::attr class if(category=="members") 'active' ::>
<a href="/member" ::cond user.canAccessMembership()::>::_("Members")::</a></li>
@@ -81,13 +81,13 @@
<li ::cond user.isAdmin():: ::attr class if(category=="admin") 'active' ::>
<a href="/admin" >::_("Admin")::</a></li>
</ul>
</div>
</nav>
::end::
<!-- Notifications -->
<div class="row">
<div id="content" class="col-md-12">
@@ -98,22 +98,22 @@
::else::
<span class="glyphicon glyphicon-ok"></span>
::end::
::raw notification.text::
::raw notification.text::
</div>
::end::
</div>
</div>
</div>
<!-- extra notification block for plugins -->
::if extraNotifBlock!=null::
::raw extraNotifBlock::
::end::
<div class="row">
::raw __content__::
</div>
</div>
<!--<div class="row">
<div class="col-md-12 alert-danger text-center" style="border-radius: 8px;margin:8px 0;padding:8px 0;">
<span class="glyphicon glyphicon-cog"></span>
@@ -123,54 +123,8 @@
</div>
</div>-->
<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>
::use 'footer.mtt'::
::end::
<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="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>
</div>
</div>
<div class="row" id="subfooter">
<span>version cagettepei-<a target="_blank" href="https://git.artcode.re/cagetters/cagettepei/src/tag/::VERSION::">::VERSION::</a></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>
::end::
</table>
</div>
</div>
::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>
+60 -52
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 -->
@@ -13,19 +13,19 @@
::else::
<span class="glyphicon glyphicon-ok"></span>
::end::
::raw notification.text::
::raw notification.text::
</div>
::end::
</div>
</div>
</div>
<div class="article">
<div class="row">
<div class="col-md-4">
<p>
::if group._image!=null::
::if group.extUrl!=null && group.extUrl!=""::
@@ -36,21 +36,21 @@
::end::
</p>
<p>
::if isMember::
<!-- connected and member of the group-->
<a href="/user/choose?amap=::group.id::" class="btn btn-primary">
<span class="glyphicon glyphicon-chevron-right"></span>
::_("Go to my account")::
</a>
::else::
<h4>Inscriptions :</h4>
::switch group._regOption::
::case::
<p>
::_("Contact the person in charge in order to subscribe to this group and get to know membership conditions.")::
@@ -71,7 +71,7 @@
::_("Subscription on waiting list")::
</a>
</p>
::case::
<p>
<a href="/group/register/::group.id::" class="btn btn-primary">
@@ -84,12 +84,12 @@
::_("This group is full and do not accept any more subscription.")::
</p>
::end::
::end::
</p>
::if user==null::
<hr />
<h4>::_("Already member? Log in:")::</h4>
@@ -97,26 +97,26 @@
<a href="#" onclick="_.loginBox('/group/::group.id::')" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-user"></span> ::_("Log in")::</a>
</div>
::end::
</div>
<div class="col-md-8">
<h2>
::group.name::
</h2>
<p>
::if group.txtIntro!=null && group.txtIntro!=""::
::raw nl2br(group.txtIntro)::
::end::
</p>
<p>
<h3> ::_("Next deliveries")::</h3>
::foreach d group.getDeliveries(4)::
<div style="display:inline-block;margin-right:8px;vertical-align:top;">
::set s = getDate( d.date )::
::if isToday(d.date)::
@@ -125,15 +125,15 @@
$$date(::s.dow::,::s.d::,::s.m::,::s.y::,::d._place::)
::end::
</div>
::end::
</p>
<hr/>
<p ::cond group._contact!=null::>
<h3>::_("Contact")::</h3>
<i class="icon-user"></i>
<b>::group._contact.firstName:: ::group._contact.lastName::</b><br/>
<span ::cond group._contact.email!=null::>
@@ -144,52 +144,60 @@
<span class="glyphicon glyphicon-phone-alt"></span> ::group._contact.phone::<br/>
</span>
</p>
<hr/>
<p>
<h3>::_("Suppliers and products")::</h3>
<p>
::_("Non-complete extract of available products:")::
</p>
::foreach c contracts::
<p>
<b>::c.name::</b><br/>
::c._vendor.name::, $$nullSafe(::c._vendor.zipCode::) $$nullSafe(::c._vendor.city::)
<div class="row">
::foreach p c.getProductsPreview(6)::
<div class="col-md-2" data-toggle="tooltip" data-placement="top" title="::p.name::" >
<div style="background-image:url('::p.getImage()::')" class="productImg"/>
<div class="col-md-2" data-toggle="tooltip" data-placement="top" title="::p.name::" >
<div style="background-image:url('::p.getImage()::')" class="productImg"/>
</div>
::end::
::end::
</div>
</p>
</p>
::end::
</p>
</div>
</div>
<div class="col-md-4">
</div>
</div>
</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>
</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>
::use 'footer.mtt'::
::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": "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.11.0"
}
{"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"}
+2 -2
View File
@@ -203,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");
@@ -280,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);
+1 -1
View File
@@ -30,7 +30,7 @@ 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 langs = App.config.get("langs", "fr").split(";");
var langNames = App.config.get("langnames", "Français").split(";");
var i = 0;
var langLinks = "";
+89 -89
View File
@@ -14,66 +14,66 @@ class Group extends controller.Controller
*/
@tpl('group/view.mtt')
function doDefault(group:db.Amap){
if (group.regOption == db.Amap.RegOption.Open) {
app.session.data.amapId = group.id;
throw Redirect("/");
}
view.group = group;
view.contracts = group.getActiveContracts();
view.pageTitle = group.name;
group.getMainPlace(); //just to update cache
if (app.user != null){
view.isMember = Lambda.has(app.user.getAmaps(), group);
}
}
/**
* Register to a waiting list.
* the user can be logged or not !
*/
@tpl('form.mtt')
function doList(group:db.Amap){
//checks
if (group.regOption != db.Amap.RegOption.WaitingList) throw Redirect("/group/" + group.id);
if (app.user != null) {
try{
WaitingListService.canRegister(app.user,group);
}catch(e:tink.core.Error){
}catch(e:tink.core.Error){
throw Error("/group/" + group.id,e.message);
}
}
//build form
var form = new sugoi.form.Form("reg");
var form = new sugoi.form.Form("reg");
if (app.user == null){
form.addElement(new StringInput("userFirstName", t._("Your firstname"),"",true));
form.addElement(new StringInput("userLastName", t._("Your lastname") ,"",true));
form.addElement(new StringInput("userEmail", t._("Your e-mail"), "", 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{
if (app.user == null){
var f = form;
var user = service.UserService.softRegistration(f.getValueOf("userFirstName"),f.getValueOf("userLastName"), f.getValueOf("userEmail") );
db.User.login(user, user.email);
}
db.User.login(user, user.email);
}
WaitingListService.registerToWl(app.user,group,form.getValueOf("msg"));
throw Ok("/group/" + group.id,t._("Your subscription to the waiting list has been recorded. You will receive an e-mail as soon as your request is processed.") );
}catch(e:tink.core.Error){
throw Error("/group/list/" + group.id,e.message);
}
}
view.title = t._("Subscription to \"::groupeName::\" waiting list", {groupeName:group.name});
view.form = form;
view.form = form;
}
/**
@@ -82,27 +82,27 @@ class Group extends controller.Controller
function doListCancel(group:db.Amap){
try{
WaitingListService.removeFromWl(app.user,group);
}catch(e:tink.core.Error){
}catch(e:tink.core.Error){
throw Error("/group/" + group.id,e.message);
}
throw Ok("/group/" + group.id,t._("You've been removed from the waiting list"));
}
/**
* Register direclty in an open group
*
*
* the user can be logged or not !
@tpl('form.mtt')
function doRegister(group:db.Amap){
if (group.regOption != db.Amap.RegOption.Open) throw Redirect("/group/" + group.id);
if (app.user != null){
if ( db.UserAmap.manager.select($amapId == group.id && $user == app.user) != null) throw Error("/group/" + group.id, t._("You are already member of this group."));
if (app.user != null){
if ( db.UserAmap.manager.select($amapId == group.id && $user == app.user) != null) throw Error("/group/" + group.id, t._("You are already member of this group."));
}
var form = new sugoi.form.Form("reg");
var form = new sugoi.form.Form("reg");
form.submitButtonLabel = t._("Join the group");
form.addElement(new sugoi.form.elements.Html("html",t._("Confirm your subscription to \"::groupName::\"", {groupName:group.name})));
if (app.user == null){
@@ -110,15 +110,15 @@ class Group extends controller.Controller
form.addElement(new StringInput("userLastName", t._("Your lastname"), "", true));
var em = new StringInput("userEmail", t._("Your e-mail"), "", true);
em.addValidator(new EmailValidator());
form.addElement(em);
form.addElement(new StringInput("address", t._("Address"), "", true));
form.addElement(new StringInput("zipCode", t._("Zip code"), "", true));
form.addElement(new StringInput("city", t._("City"), "", true));
form.addElement(new StringInput("phone", t._("Phone"), "", true));
form.addElement(em);
form.addElement(new StringInput("address", t._("Address"), "", true));
form.addElement(new StringInput("zipCode", t._("Zip code"), "", true));
form.addElement(new StringInput("city", t._("City"), "", true));
form.addElement(new StringInput("phone", t._("Phone"), "", true));
}
if (form.isValid()){
if (app.user == null){
var f = form;
var user = new db.User();
@@ -129,92 +129,92 @@ class Group extends controller.Controller
user.zipCode = f.getValueOf("zipCode");
user.city = f.getValueOf("city");
user.phone = f.getValueOf("phone");
if ( db.User.getSameEmail(user.email).length > 0 ) {
throw Ok("/user/login",t._("You already subscribed to Cagette.net, please log in on this page"));
}
user.insert();
user.insert();
app.session.setUser(user);
}
}
var w = new db.UserAmap();
w.user = app.user;
w.amap = group;
w.insert();
throw Ok("/user/choose", t._("Your subscription has been taken into account"));
}
view.title = t._("Subscription to \"::groupName::\"", {groupName:group.name});
view.form = form;
}*/
/**
* create a new group
*/
@tpl("form.mtt")
function doCreate() {
view.title = t._("Create a new Cagette Group");
var f = new sugoi.form.Form("c");
f.addElement(new StringInput("name", t._("Name of your group"), "", true));
//group type
var data = [
{label:t._("CSA"),value:"0"},
{label:t._("Grouped orders"),value:"1"},
{label:t._("Farmers collective"),value:"2"},
{label:t._("Farm shop"),value:"3"},
];
];
var gt = new sugoi.form.elements.RadioGroup("type", t._("Group type"), data ,"1","1",true,true,true);
f.addElement(gt);
if (f.checkToken()) {
var user = app.user;
var g = new db.Amap();
g.name = f.getValueOf("name");
g.contact = user;
var type:db.Amap.GroupType = Type.createEnumIndex(db.Amap.GroupType, Std.parseInt(f.getValueOf("type")) );
switch(type){
case null :
case null :
throw "unknown group type";
case db.Amap.GroupType.Amap :
case db.Amap.GroupType.Amap :
g.flags.set(db.Amap.AmapFlags.HasMembership);
g.regOption = db.Amap.RegOption.WaitingList;
case db.Amap.GroupType.GroupedOrders :
g.flags.set(db.Amap.AmapFlags.ShopMode);
g.flags.set(db.Amap.AmapFlags.HasMembership);
g.regOption = db.Amap.RegOption.WaitingList;
case db.Amap.GroupType.ProducerDrive :
case db.Amap.GroupType.ProducerDrive :
g.flags.set(db.Amap.AmapFlags.ShopMode);
g.regOption = db.Amap.RegOption.Open;
g.flags.set(db.Amap.AmapFlags.PhoneRequired);
case db.Amap.GroupType.FarmShop :
case db.Amap.GroupType.FarmShop :
g.flags.set(db.Amap.AmapFlags.ShopMode);
g.regOption = db.Amap.RegOption.Open;
g.flags.set(db.Amap.AmapFlags.PhoneRequired);
}
g.groupType = type;
g.insert();
var ua = new db.UserAmap();
ua.user = user;
ua.amap = g;
ua.rights = [db.UserAmap.Right.GroupAdmin,db.UserAmap.Right.Membership,db.UserAmap.Right.Messages,db.UserAmap.Right.ContractAdmin(null)];
ua.insert();
//example datas
var place = new db.Place();
place.name = t._("Market square");
@@ -222,7 +222,7 @@ class Group extends controller.Controller
place.city = "St Martin de la Cagette";
place.amap = g;
place.insert();
//contrat AMAP
var vendor = new db.Vendor();
vendor.amap = g;
@@ -230,8 +230,8 @@ class Group extends controller.Controller
vendor.zipCode = "000";
vendor.city = "Langon";
vendor.email = "jean@cagette.net";
vendor.insert();
vendor.insert();
if (type == Amap){
var contract = new db.Contract();
contract.name = t._("CSA contract Vegetables - Example");
@@ -244,32 +244,32 @@ class Group extends controller.Controller
contract.contact = user;
contract.distributorNum = 2;
contract.insert();
var p = new db.Product();
p.name = t._("Big basket of vegetables");
p.price = 15;
p.organic = true;
p.contract = contract;
p.insert();
var p = new db.Product();
p.name = t._("Small basket of vegetables");
p.price = 10;
p.organic = true;
p.contract = contract;
p.insert();
OrderService.make(user, 1, p, null, true);
var d = new db.Distribution();
d.contract = contract;
d.date = DateTools.delta(Date.now(), 1000.0 * 60 * 60 * 24 * 14);
d.end = DateTools.delta(d.date, 1000.0 * 60 * 90);
d.place = place;
d.insert();
}
//contrat variable
var vendor = new db.Vendor();
vendor.amap = g;
@@ -277,8 +277,8 @@ class Group extends controller.Controller
vendor.zipCode = "000";
vendor.city = t._("Bazas");
vendor.email = "galinette@cagette.net";
vendor.insert();
vendor.insert();
var contract = new db.Contract();
contract.name = t._("Chicken Contract - Example");
contract.description = t._("Example of contract with variable orders. It is allowed to order something else at every delivery.");
@@ -291,7 +291,7 @@ class Group extends controller.Controller
contract.distributorNum = 2;
contract.flags.set(db.Contract.ContractFlags.UsersCanOrder);
contract.insert();
var egg = new db.Product();
egg.name = t._("12 eggs");
egg.price = 5;
@@ -299,7 +299,7 @@ class Group extends controller.Controller
egg.organic = true;
egg.contract = contract;
egg.insert();
var p = new db.Product();
p.name = t._("Chicken");
//p.type = 2;
@@ -307,7 +307,7 @@ class Group extends controller.Controller
p.organic = true;
p.contract = contract;
p.insert();
var d = new db.Distribution();
d.contract = contract;
d.orderStartDate = Date.now();
@@ -316,36 +316,36 @@ class Group extends controller.Controller
d.end = DateTools.delta(d.date, 1000.0 * 60 * 90);
d.place = place;
d.insert();
OrderService.make(user, 2, egg, d.id);
OrderService.make(user, 1, p, d.id);
App.current.session.data.amapId = g.id;
app.session.data.newGroup = true;
throw Redirect("/");
}
view.form= f;
}
/**
Displays a google map in a popup
**/
@tpl('group/place.mtt')
public function doPlace(place:db.Place){
view.place = place;
//build adress for google maps
var addr = "";
if (place.address1 != null) addr += place.address1;
if (place.address2 != null) addr += ", " + place.address2;
if (place.zipCode != null) addr += " " + place.zipCode;
if (place.city != null) addr += " " + place.city;
view.addr = view.escapeJS(addr);
}
/**
* Groups map
*/
@@ -353,16 +353,16 @@ class Group extends controller.Controller
public function doMap(?args:{?lat:Float,?lng:Float,?address:String}){
view.container = "container-fluid";
//if no param is sent, focus on Paris
if (args == null || (args.address == null && args.lat == null && args.lng == null)){
args = {lat:48.855675, lng:2.3472365};
}
view.lat = args.lat;
view.lng = args.lng;
view.address = args.address;
view.address = args.address;
}
}
+85 -89
View File
@@ -1,4 +1,5 @@
package controller;
import db.Distribution;
import db.UserContract;
import haxe.Json;
@@ -9,149 +10,147 @@ import Common;
import tools.ArrayTool;
class Main extends Controller {
/**
* public pages
* public pages
*/
function doGroup(d:haxe.web.Dispatch){
function doGroup(d:haxe.web.Dispatch) {
d.dispatch(new controller.Group());
}
/**
Group homepage
Group homepage
**/
@tpl("home.mtt")
function doDefault() {
view.category = 'home';
var group = app.getCurrentGroup();
if ( app.user!=null && group == null) {
var group = app.getCurrentGroup();
if (app.user != null && group == null) {
throw Redirect("/user/choose");
}else if (app.user == null && (group==null || group.regOption!=db.Amap.RegOption.Open) ) {
throw Redirect("/user/login");
} 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);
//freshly created group
// register to become "distributor"
view.contractsWithDistributors = app.user == null ? [] : Lambda.filter(app.user.amap.getActiveContracts(), function(c) return c.distributorNum > 0);
// 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());
}
function doCron(d:Dispatch) {
d.dispatch(new controller.Cron());
}
/**
* 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
sugoi.Web.setReturnCode(500);
var stack = if ( App.config.DEBUG ) haxe.CallStack.toString(haxe.CallStack.exceptionStack()) else "";
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 "";
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")
function doCssdemo() {
view.category = 'home';
}
@tpl("form.mtt")
function doInstall(d:Dispatch) {
d.dispatch(new controller.Install());
}
function doP(d:Dispatch) {
/*
* Invalid array access
Stack (ADMIN|DEBUG)
* Invalid array access
Stack (ADMIN|DEBUG)
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) {
var n = Type.getClassName(Type.getClass(p)).toLowerCase();
n = n.split(".").pop();
if (plugin == n) {
d.dispatch( p.getController() );
return;
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) {
var n = Type.getClassName(Type.getClass(p)).toLowerCase();
n = n.split(".").pop();
if (plugin == n) {
d.dispatch( p.getController() );
return;
}
}
}
throw Error("/","Plugin '"+plugin+"' introuvable.");
*/
throw Error("/","Plugin '"+plugin+"' introuvable.");
*/
d.dispatch(new controller.Plugin());
}
@logged
function doMember(d:Dispatch) {
view.category = 'members';
d.dispatch(new controller.Member());
}
@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';
@@ -163,31 +162,31 @@ Called from controller/Main.hx line 117
view.category = 'contractadmin';
d.dispatch(new controller.Vendor());
}
@logged
function doPlace(d:Dispatch) {
view.category = 'contractadmin';
d.dispatch(new controller.Place());
}
@logged
function doTransaction(d:Dispatch) {
view.category = 'members';
d.dispatch(new controller.Transaction());
}
@logged
function doDistribution(d:Dispatch) {
view.category = 'contractadmin';
d.dispatch(new controller.Distribution());
}
@logged
function doMembership(d:Dispatch) {
view.category = 'members';
d.dispatch(new controller.Membership());
}
function doShop(d:Dispatch) {
view.category = 'shop';
d.dispatch(new controller.Shop());
@@ -199,63 +198,60 @@ Called from controller/Main.hx line 117
view.place = place;
view.date = date;
}
@logged
function doProduct(d:Dispatch) {
view.category = 'contractadmin';
d.dispatch(new controller.Product());
}
@logged
function doAmap(d:Dispatch) {
view.category = 'amap';
d.dispatch(new controller.Amap());
}
@logged
function doContract(d:Dispatch) {
view.category = 'contract';
d.dispatch(new Contract());
}
@logged
function doContractAdmin(d:Dispatch) {
view.category = 'contractadmin';
d.dispatch(new ContractAdmin());
}
@logged
function doMessages(d:Dispatch) {
view.category = 'messages';
d.dispatch(new Messages());
}
@logged
function doAmapadmin(d:Dispatch) {
view.category = 'amapadmin';
d.dispatch(new AmapAdmin());
}
@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;
v.user = user;
v.user = user;
d.dispatch(v);
}
@admin
function doAdmin(d:Dispatch) {
d.dispatch(new controller.admin.Admin());
}
@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");
}
}
+15
View File
@@ -30,6 +30,21 @@ class User extends Controller {
}
}
@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.
*/
+77 -108
View File
@@ -1,138 +1,122 @@
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")
function doDefault() {
view.now = Date.now();
}
@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 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");
f.addElement(new sugoi.form.elements.StringSelect("mailer", "Mailer", data, mailer ));
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 ? "<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.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");
view.form = f;
}
function doPlugins(d:Dispatch) {
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,84 +124,69 @@ 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() {
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;
for (order in basket.getOrders()){
if (basket == null || basket.isValidated())
continue;
for (order in basket.getOrders()) {
if (!order.paid) {
Sys.println(order.distribution.toString() + "<br>");
Sys.println(order.toString() + "<br>");
}
}
}
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 ====");
}
}
+22 -29
View File
@@ -1,46 +1,39 @@
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)
{
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>";
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>";
s += "<label for=\"" + n + c + "\" class='checkbox' style='display: inline-block;'>" + radio + " " + img + " </label>";
c++;
}
}
}
return s;
}
}
}
+7 -5
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();
@@ -39,7 +41,7 @@ class WaitingListService{
public static function canRegister(user:db.User,group:db.Amap){
var t = sugoi.i18n.Locale.texts;
if ( db.WaitingList.manager.select($amapId == group.id && $user == user) != null) {
throw new Error(t._("You are already in the waiting list of this group"));
}
@@ -91,7 +93,7 @@ class WaitingListService{
group
);
}
wl.delete();
}
@@ -108,9 +110,9 @@ class WaitingListService{
var ua = new db.UserAmap();
ua.amap = wl.group;
ua.user = wl.user;
ua.insert();
ua.insert();
}
wl.delete();
//email the requester
@@ -131,7 +133,7 @@ class WaitingListService{
group
);
}
wl.delete();
}
+22 -20
View File
@@ -13,26 +13,28 @@ class BaseView implements Dynamic {
public function init() {
var app = App.current;
this.user = app.user;
this.session = app.session;
this.LANG = App.config.LANG;
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;
if ( App.config.SQL_LOG ) {
this.Config = App.config;
if ( App.config.SQL_LOG ) {
this.sqlLog = untyped app.cnx == null ? null : app.cnx.log;
}
}
function getMessage() {
var session = App.current.session;
if ( session == null ) return null;
@@ -41,14 +43,14 @@ class BaseView implements Dynamic {
if( n == null ) return null;
return { text : n.text, error : n.error, next : session.messages.length > 0 };
}
function getMessages() {
var out = [];
var session = App.current.session;
if ( session == null ) return [];
if (session.messages == null) return [];
for ( m in session.messages) {
if( m == null ) continue;
out.push( { text : m.text, error : m.error } );
@@ -56,12 +58,12 @@ class BaseView implements Dynamic {
session.messages = [];
return out;
}
function urlEncode(str:String) {
return StringTools.urlEncode(str);
}
/**
* To safely print a string in javascript
* @param str
@@ -70,13 +72,13 @@ class BaseView implements Dynamic {
if (str == null) return "";
return str.split("\\").join("\\\\").split("'").join("\\'").split("\r").join("\\r").split("\n").join("\\n");
}
/**
* Get a value from the Variable table
* @param file
*/
function getVariable( file : String ) {
var v = _vcache.get(file);
if( v != null )
return v;
@@ -91,7 +93,7 @@ class BaseView implements Dynamic {
function getParam( p : String ) {
return App.current.params.get(p);
}
/**
* Return the url of a db.File record
*/
@@ -99,7 +101,7 @@ class BaseView implements Dynamic {
if (file == null) throw "file is null";
return "/file/"+sugoi.db.File.makeSign(file.id)+"."+file.getExtension();
}
/**
* Try to print an HTML table from any kind of object
* @param data
@@ -107,14 +109,14 @@ class BaseView implements Dynamic {
function table(data:Dynamic) {
return new sugoi.helper.Table("table table-bordered").toString(data);
}
/**
* newline to <br/>
* @param txt
*/
public function nl2br(txt:String):String {
public function nl2br(txt:String):String {
if (txt == null) return "";
return txt.split("\n").join("<br/>");
return txt.split("\n").join("<br/>");
}
@@ -125,7 +127,7 @@ class BaseView implements Dynamic {
return str;
}
}
//same function with params ( templo doesnt manage optionnal params in functions )
public function __(str:String, params:Dynamic){
return sugoi.i18n.Locale.texts.get(str, params);
@@ -136,7 +138,7 @@ class BaseView implements Dynamic {
neko.Web.logMessage("_call "+str);
return StringTools.rtrim( str.split("||")[0] );
}
//same function with params ( templo doesnt manage optionnal params in functions )
public function __(str:String, params:Dynamic):String {
neko.Web.logMessage("_call "+str);
@@ -159,5 +161,5 @@ class BaseView implements Dynamic {
}
return list;
}
}
+2
View File
@@ -11,6 +11,7 @@ class Config {
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;
@@ -28,6 +29,7 @@ class Config {
TPL = PATH + "lang/" + LANG + "/tpl/";
TPL_TMP = PATH + "lang/" + LANG + "/tmp/";
DEBUG = get("debug", "0") == "1";
BANDEAU_REGION = get("bandeau_region", "0") == "1";
HOST = get("host");
KEY = get("key");
DATA_HOST = get("dataHost", "data." + HOST);
+633 -682
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: 112 KiB

+1
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"