-o .```
3 | * restore db ```mongorestore --drop -h localhost -d karibou-deve```
4 |
--------------------------------------------------------------------------------
/docs/data/cart.json:
--------------------------------------------------------------------------------
1 | {
2 | '_id': 'objectid',
3 | 'user_id': 'objectid',
4 | 'state': 'cart',
5 |
6 | 'line_items': [
7 | {'sku': 'jc-432',
8 | 'name': 'John Coltrane: A Love Supreme',
9 | 'retail_price': 1099
10 | },
11 |
12 | {'sku': 'ly-211',
13 | 'name': 'Larry Young: Unity',
14 | 'retail_price': 1199
15 | },
16 | ],
17 |
18 | 'shipping_address': {
19 | 'street': '3333 Greene Ave.',
20 | 'city': 'Brooklyn',
21 | 'state': 'NY',
22 | 'zip': '11216'
23 | },
24 |
25 | 'subtotal': 2199
26 | }
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docs/data/cors-middleware-express-with-proxy.js:
--------------------------------------------------------------------------------
1 | // node.js proxy server example for adding CORS headers to any existing http services.
2 | // yes, i know this is super basic, that's why it's here. use this to help understand how http-proxy works with express if you need future routing capabilities
3 |
4 | var httpProxy = require('http-proxy'),
5 | express = require('express');
6 |
7 | var proxy = new httpProxy.RoutingProxy();
8 |
9 | var proxyOptions = {
10 | host: '192.168.3.11',
11 | port: 8080
12 | };
13 |
14 | var app = express.createServer();
15 |
16 | var allowCrossDomain = function(req, res, next) {
17 | console.log('allowingCrossDomain');
18 | res.header('Access-Control-Allow-Origin', '*');
19 | res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
20 | res.header('Access-Control-Allow-Headers', 'X-Requested-With, Accept, Origin, Referer, User-Agent, Content-Type, Authorization, X-Mindflash-SessionID');
21 |
22 | // intercept OPTIONS method
23 | if ('OPTIONS' == req.method) {
24 | res.send(200);
25 | }
26 | else {
27 | next();
28 | }
29 | };
30 |
31 | app.configure(function() {
32 | app.use(allowCrossDomain);
33 | });
34 |
35 | app.all('/*', function (req, res) {
36 | return proxy.proxyRequest(req, res, proxyOptions);
37 | });
38 |
39 | app.listen(9000);
40 |
41 | console.log('#########\nListening on 9000\n##########');
--------------------------------------------------------------------------------
/docs/data/product-coop.html:
--------------------------------------------------------------------------------
1 |
42 |
--------------------------------------------------------------------------------
/docs/data/products-a.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "My Awesome T-shirt",
4 | "description": "All about the details. Of course it's black.",
5 |
6 | "image": {
7 | "source": "picture.io",
8 | "url": "images/products/1234/main.jpg"
9 | },
10 |
11 |
12 | "categories": [
13 | { "name": "Clothes" },
14 | { "name": "Shirts" }
15 | ],
16 | "style": "1234",
17 | "variants": [
18 | {
19 | "color": "Black",
20 | "images": [
21 | {
22 | "kind": "thumbnail",
23 | "url": "images/products/1234/thumbnail.jpg"
24 | },
25 | {
26 | "kind": "catalog",
27 | "url": "images/products/1234/black.jpg"
28 | }
29 | ],
30 | "sizes": [
31 | {
32 | "size": "S",
33 | "available": 10,
34 | "sku": "CAT-1234-Blk-S",
35 | "price": 99.99
36 | },
37 | {
38 | "size": "M",
39 | "available": 7,
40 | "sku": "CAT-1234-Blk-M",
41 | "price": 109.99
42 | }
43 | ]
44 | }
45 | ],
46 | "catalogs": [
47 | { "name": "Apparel" }
48 | ]
49 | }
50 | ]
51 |
52 |
--------------------------------------------------------------------------------
/docs/data/products-b.json:
--------------------------------------------------------------------------------
1 |
2 | // db.products.find({'_id': ObjectID("4bd87bd8277d094c458d2fa5")});
3 |
4 | [
5 | {
6 | title: "Pâtes complètes à l'épeautre ''bio reconversion'' 500g",
7 |
8 |
9 |
10 | /* produits */
11 | details:{
12 | description:"Cultivé depuis l’Egypte Antique, l’épeautre a peu....",
13 | remarque:"Garder au sec et surveiller le temps de cuisso...",
14 | conservation:{"3 semaines après la date de livraison", isotherme:true},
15 | },
16 | attributs:{ bio:Boolean, promote:Boolean},
17 |
18 | producteur:[Producteur],
19 |
20 | /* panier */
21 | details:{
22 | },
23 |
24 | /* audio */
25 | details: {
26 | number_of_discs: 1,
27 | label: "Impulse Records",
28 | issue_date: "December 9, 1964",
29 | average_customer_review: 4.95,
30 | asin: "B0000A118M"
31 | },
32 |
33 | bio:true,
34 | promo:true,
35 |
36 |
37 | "vendor":ObjectId,
38 |
39 |
40 | "pricing": {
41 | "list": 1198,
42 | "retail": 1099,
43 | "savings": 99,
44 | "pct_savings": 8
45 | },
46 |
47 | "categories": [
48 | ObjectID,
49 | ObjectID,
50 | ObjectID
51 | ]
52 | }
53 | ]
54 |
--------------------------------------------------------------------------------
/docs/data/user.json:
--------------------------------------------------------------------------------
1 | http://portablecontacts.net/draft-spec.html#schema
2 |
3 | {
4 | "id": "703887",
5 | "displayName": "Mork Hashimoto",
6 | "name": {
7 | "familyName": "Hashimoto",
8 | "givenName": "Mork"
9 | },
10 | "birthday": "0000-01-16",
11 | "gender": "male",
12 | "drinker": "heavily",
13 | "tags": [
14 | "plaxo guy",
15 | "favorite"
16 | ],
17 | "emails": [
18 | {
19 | "value": "mhashimoto-04@plaxo.com",
20 | "type": "work",
21 | "primary": "true"
22 | },
23 | {
24 | "value": "mhashimoto-04@plaxo.com",
25 | "type": "home"
26 | },
27 | {
28 | "value": "mhashimoto@plaxo.com",
29 | "type": "home"
30 | }
31 | ],
32 | "urls": [
33 | {
34 | "value": "http://www.seeyellow.com",
35 | "type": "work"
36 | },
37 | {
38 | "value": "http://www.angryalien.com",
39 | "type": "home"
40 | }
41 | ],
42 | "phoneNumbers": [
43 | {
44 | "value": "KLONDIKE5",
45 | "type": "work"
46 | },
47 | {
48 | "value": "650-123-4567",
49 | "type": "mobile"
50 | }
51 | ],
52 | "photos": [
53 | {
54 | "value": "http://sample.site.org/photos/12345.jpg",
55 | "type": "thumbnail"
56 | }
57 | ],
58 | "ims": [
59 | {
60 | "value": "plaxodev8",
61 | "type": "aim"
62 | }
63 | ],
64 | "addresses": [
65 | {
66 | "type": "home",
67 | "streetAddress": "742 Evergreen Terrace\nSuite 123",
68 | "locality": "Springfield",
69 | "region": "VT",
70 | "postalCode": "12345",
71 | "country": "USA",
72 | "formatted": "742 Evergreen Terrace\nSuite 123\nSpringfield, VT 12345 USA"
73 | }
74 | ],
75 | "organizations": [
76 | {
77 | "name": "Burns Worldwide",
78 | "title": "Head Bee Guy"
79 | }
80 | ],
81 | "shop": [
82 | "shop": ObjectID,
83 | "promary": true
84 | }
85 | ]
86 | }
87 |
--------------------------------------------------------------------------------
/emails/billing/text.ejs:
--------------------------------------------------------------------------------
1 | Bonjour Olivier,
2 |
3 | Nous vous remercions pour votre commande du XX.2014.
4 | Vous trouverez ci-dessous le détail de votre commande
5 | =====================================================
6 | * 1x Chaussons aux poire (250gr) 3.00 CHF
7 | * 2x Bananes (bio) 5.00 CHF
8 | * 1x riz basmati blanc (500gr) 5.00 CHF
9 | * 1x Huile d'olive extra vierge (1L) 12.00 CHF
10 | * --------------------------------------------
11 | * Sous total 132.50 CHF
12 | * Frais de livraison 10.00 CHF
13 | * Frais de paiement 0.00 CHF
14 | * --------------------------------------------
15 | * Montant total (provisoire) 123.50 CHF
16 |
17 |
18 | RÉCAPITULATIF
19 | =============
20 | Numéro de commande: TX000000001
21 | Méthode de paiement: Bulletin de versement
22 | Montant total provisiore: 123.50 CHF
23 | Date de livraison: mercredi 12 décembre entre 16:00 et 18:00
24 | Adresse de livraison:
25 | Olivier Evalet
26 | 34, route de Chene
27 | 1208,Genève
28 |
29 | PAIEMENT ET MONTANT
30 | ===================
31 | Vous recevrez une facture détaillée par e-mail avant la livraison.
32 | Le total de la commande peut être différent de la facture finale à régler
33 | * Il prend en compte le prix moyen des produits à poids variable
34 | * Si un produit devait être en rupture de stock, il sera déduit de la facture finale.
35 |
36 |
37 |
38 | MERCI,
39 |
40 | | |/ / (_) |
41 | | ' / __ _ _ __ _| |__ ___ _ _
42 | | < / _` | '__| | '_ \ / _ \| | | |
43 | | . \ (_| | | | | |_) | (_) | |_| |
44 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
45 |
46 |
--------------------------------------------------------------------------------
/emails/confirm/html.ejs:
--------------------------------------------------------------------------------
1 | Bonjour <%= name.givenName %>,
2 |
3 | Afin de valider votre compte, merci de bien vouloir confirmer votre adresse e-mail en cliquant sur le lien suivant:
4 | <%= origin %>/validate/<%= validate.uid %>/<%= validate.email %>
5 |
6 | A bientôt,
7 |
8 | --
9 | Olivier Evalet
10 | de l'équipe Karibou.
11 |
12 |
--------------------------------------------------------------------------------
/emails/confirm/text.ejs:
--------------------------------------------------------------------------------
1 | Bonjour <%= name.givenName %>,
2 |
3 | Afin de valider votre compte, merci de bien vouloir confirmer votre adresse e-mail en cliquant sur le lien suivant:
4 | <%= origin %>/validate/<%= validate.uid %>/<%= validate.email %>
5 |
6 | A bientot,
7 |
8 | --
9 | Olivier Evalet
10 | de l'équipe Karibou.
11 |
12 |
--------------------------------------------------------------------------------
/emails/karibou-question/html.ejs:
--------------------------------------------------------------------------------
1 | <%if (develMode) {%>
2 | TEST -- TEST -- TEST
3 | <% } %>Bonjour,
4 | L'utilisateur <%= user %> à une question :
5 | <% if(typeof product !== 'undefined') { %>
6 | Pour le produit: <%= product %>
7 | <% } %><% if(typeof mood !== 'undefined') { %>
8 | Concerne: <%= mood %>
9 | <% } %>
10 |
11 | <%= text %>
12 |
13 | Avec nos meilleurs messages,
14 |
15 | | |/ / (_) |
16 | | ' / __ _ _ __ _| |__ ___ _ _
17 | | < / _` | '__| | '_ \ / _ \| | | |
18 | | . \ (_| | | | | |_) | (_) | |_| |
19 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
20 |
--------------------------------------------------------------------------------
/emails/karibou-question/text.ejs:
--------------------------------------------------------------------------------
1 | Hello,
2 | L'utilisateur <%= user %> (<%= email %>) à une question :
3 | <% if(typeof product !== 'undefined') { %>
4 | Pour le produit: <%= product %>
5 | <% } %><% if(typeof mood !== 'undefined') { %>
6 | Concerne: <%= mood %>
7 | <% } %>
8 |
9 | <%= text %>
10 |
11 | Avec nos meilleurs messages,
12 |
13 | | |/ / (_) |
14 | | ' / __ _ _ __ _| |__ ___ _ _
15 | | < / _` | '__| | '_ \ / _ \| | | |
16 | | . \ (_| | | | | |_) | (_) | |_| |
17 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
18 |
--------------------------------------------------------------------------------
/emails/order-billing/html.ejs:
--------------------------------------------------------------------------------
1 | <%if (develMode) {%>
2 | TEST -- TEST -- TEST
3 | <% } %>Bonjour <%= order.customer.name.givenName %>,
4 |
5 | Veuillez trouver votre facture Karibou pour votre commande <%= order.oid %> du <%= created %>.
6 |
7 |
8 | *<% for(var i=0; i
9 | * <%if (order.items[i].fulfillment.status==='failure') {%><%}%><%= order.items[i].quantity %>x <%- order.items[i].title %> (<%- order.items[i].part %>) <%= order.items[i].finalprice.toFixed(2) %> CHF <%if (order.items[i].fulfillment.status==='failure') {%><%}%><%if (order.items[i].variant&&order.items[i].variant.title) {%>
10 | * option: <%= order.items[i].variant.title %><% } %><% } %>
11 | * ------------------
12 | * Sous total <%= subTotal %> CHF
13 | * Frais de livraison <%= shippingFees %> CHF
14 | * Frais de paiement <%= paymentFees %> CHF<%if (extraDiscount>0) {%>
15 | * Bonus commerçants -<%= extraDiscount %> CHF<% } %>
16 | * ------------------
17 | * Montant total <%= totalWithFees %> CHF<%if (totalDiscount>0) {%>
18 | * Rabais commerçants <%= totalDiscount %> CHF<% } %>
19 | *
20 |
21 | <%if (order.payment.issuer==='invoice') {%>
22 |
23 |
24 | Veuillez effectuer le virement bancaire (BVR) dans les 10 jours:
25 | (1) - Compte: 14-615643-8 ou CH76 0900 0000 1461 5643 8 / BIC: POFICHBEXXX
26 | (2) - Montant à payer, <%= totalWithFees %> CHF
27 | (3) - Motif versement, <%= order.customer.id %><%= order.oid %>
28 | (4) - Versement pour: Karibou Delphine Cluzel Evalet et Olivier Evalet, CH-1208 Genève
29 |
30 |
31 | <% } %>
32 |
33 | Pour toute question, veuillez répondre à ce mail.
34 | Avec nos meilleurs messages,
35 |
36 | | |/ / (_) |
37 | | ' / __ _ _ __ _| |__ ___ _ _
38 | | < / _` | '__| | '_ \ / _ \| | | |
39 | | . \ (_| | | | | |_) | (_) | |_| |
40 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|.ch
41 |
42 |
43 | ----
44 | Toutes vos commandes <%= origin %>/account/orders
45 |
--------------------------------------------------------------------------------
/emails/order-billing/html.invoice_ejs:
--------------------------------------------------------------------------------
1 | Bonjour <%= order.customer.name.givenName %>,
2 |
3 | Veuillez trouver votre facture Karibou pour votre commande <%= order.oid %> du <%= created %>.
4 | Veuillez utiliser cette référence pour le paiement avant le 30.12.2014:
5 | (1) - Compte: CH76 0900 0000 1461 5643 8 / BIC: POFICHBEXXX
6 | (2) - Montant à payer, <%= totalWithFees %> CHF
7 | (4) - Versement pour: Karibou Delphine Cluzel Evalet et Olivier Evalet, CH-1208 Genève
8 |
9 |
10 | *<% for(var i=0; i
11 | * <%= order.items[i].quantity %>x <%- order.items[i].title %> (<%- order.items[i].part %>) <%= order.items[i].finalprice.toFixed(2) %> CHF <% } %>
12 | * ------------------
13 | * Sous total <%= subTotal %> CHF
14 | * Frais de livraison <%= shippingFees %> CHF
15 | * Frais de paiement <%= paymentFees %> CHF
16 | * ------------------
17 | * Montant total <%= totalWithFees %> CHF
18 | *
19 |
20 |
21 | Pour toute question, veuillez répondre à ce mail.
22 | Avec nos meilleurs messages,
23 |
24 | | |/ / (_) |
25 | | ' / __ _ _ __ _| |__ ___ _ _
26 | | < / _` | '__| | '_ \ / _ \| | | |
27 | | . \ (_| | | | | |_) | (_) | |_| |
28 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
29 |
30 |
31 | ----
32 | Toutes vos commandes <%= origin %>/account/orders
33 |
--------------------------------------------------------------------------------
/emails/order-billing/text.ejs:
--------------------------------------------------------------------------------
1 | <%if (develMode) {%>
2 | *TEST -- TEST -- TEST
3 | <% } %>Bonjour <%= order.customer.name.givenName %>,
4 |
5 | Veuillez trouver votre facture Karibou pour votre commande <%= order.oid %> du <%= created %>.
6 |
7 |
8 | *<% for(var i=0; i
9 | * <%if (order.items[i].fulfillment.status==='failure') {%><%}%><%= order.items[i].quantity %>x <%- order.items[i].title %> (<%- order.items[i].part %>) <%= order.items[i].finalprice.toFixed(2) %> CHF <%if (order.items[i].fulfillment.status==='failure') {%><%}%><%if (order.items[i].variant&&order.items[i].variant.title) {%>
10 | * option: <%= order.items[i].variant.title %><% } %><% } %>
11 | * ------------------
12 | * Sous total <%= subTotal %> CHF
13 | * Frais de livraison <%= shippingFees %> CHF
14 | * Frais de paiement <%= paymentFees %> CHF
15 | * ------------------
16 | * Montant total <%= totalWithFees %> CHF
17 | *
18 |
19 | <%if (order.payment.issuer==='invoice') {%>
20 |
21 |
22 | * virement bancaire dans les 1
23 | (1) - Compte: 14-615643-8 ou CH76 0900 0000 1461 5643 8 / BIC: POFICHBEXXX
24 | (2) - Montant à payer, <%= totalWithFees %> CHF
25 | (3) - Motif versement, <%= order.customer.id %><%= order.oid %>
26 | (4) - Versement pour: Karibou Delphine Cluzel Evalet et Olivier Evalet, CH-1208 Genève
27 |
28 | <% } %>
29 |
30 | Pour toute question, veuillez répondre à ce mail.
31 | Avec nos meilleurs messages,
32 | | |/ / (_) |
33 | | ' / __ _ _ __ _| |__ ___ _ _
34 | | < / _` | '__| | '_ \ / _ \| | | |
35 | | . \ (_| | | | | |_) | (_) | |_| |
36 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
37 |
38 | ----
39 | Toutes vos commandes <%= origin %>/account/orders
40 |
--------------------------------------------------------------------------------
/emails/order-cancel/html.ejs:
--------------------------------------------------------------------------------
1 | <%if (develMode) {%>
2 | TEST -- TEST -- TEST
3 | <% } %>Bonjour <%= order.customer.name.givenName %>,
4 |
5 | Votre commande <%= order.oid %> du <%= created %> à bien été annulée.
6 | Avec nos meilleurs messages,
7 |
8 | | |/ / (_) |
9 | | ' / __ _ _ __ _| |__ ___ _ _
10 | | < / _` | '__| | '_ \ / _ \| | | |
11 | | . \ (_| | | | | |_) | (_) | |_| |
12 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
13 |
14 |
15 | ----
16 | vos commandes <%= origin %>/account/orders
17 |
--------------------------------------------------------------------------------
/emails/order-cancel/text.ejs:
--------------------------------------------------------------------------------
1 | Bonjour <%= order.customer.name.givenName %>,
2 |
3 | Votre commande <%= order.oid %> du <%= created %> à bien été annulée.
4 | Avec nos meilleurs messages,
5 |
6 | | |/ / (_) |
7 | | ' / __ _ _ __ _| |__ ___ _ _
8 | | < / _` | '__| | '_ \ / _ \| | | |
9 | | . \ (_| | | | | |_) | (_) | |_| |
10 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
11 |
12 |
13 | ----
14 | vos commandes <%= origin %>/account/orders
15 |
--------------------------------------------------------------------------------
/emails/order-new/text.ejs:
--------------------------------------------------------------------------------
1 | Bonjour <%= order.customer.name.givenName %>,
2 |
3 | Nous vous remercions pour votre commande du <%= created %>.
4 | Vous trouverez ci-dessous le détail de votre commande
5 | *<% for(var i=0; i
6 | * <%= order.items[i].quantity %>x <%- order.items[i].title %> (<%- order.items[i].part %>) <%= order.items[i].finalprice.toFixed(2) %> CHF <% } %>
7 | * ------------------
8 | * Sous total <%= subTotal %> CHF
9 | * Frais de livraison <%= shippingFees %> CHF
10 | * Frais de paiement <%= paymentFees %> CHF
11 | * ------------------
12 | * Montant total provisoire <%= totalWithFees %> CHF
13 | *
14 |
15 | Récapitulatif
16 | -------------
17 | Numéro de commande: <%= order.oid %>
18 | Méthode de paiement: <%= order.payment.issuer %>
19 | Montant total provisoire: <%= totalWithFees %> CHF
20 | Date de livraison: Le <%= shippingWhen %>
21 | Adresse de livraison:
22 | # <%- order.shipping.name %>
23 | # <%- order.shipping.streetAdress %>
24 | # <%- order.shipping.postalCode %>, <%- order.shipping.region %>
25 |
26 | Paiement et montant
27 | -------------------
28 | Vous recevrez une facture détaillée par e-mail avant la livraison.
29 | Le total de la commande peut être ajusté dans le cas où vous avez commandé des produits à poids variables dont le prix est connu le jour de la livraison.
30 | Aussi, si un produit devait être en rupture de stock, il sera déduit de la facture finale.
31 |
32 | Pour toute question, veuillez répondre à ce mail.
33 | Avec nos meilleurs messages,
34 |
35 | | |/ / (_) |
36 | | ' / __ _ _ __ _| |__ ___ _ _
37 | | < / _` | '__| | '_ \ / _ \| | | |
38 | | . \ (_| | | | | |_) | (_) | |_| |
39 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
40 |
41 | ----
42 | Toutes vos commandes <%= origin %>/account/orders
43 |
--------------------------------------------------------------------------------
/emails/order-prepare/text.ejs:
--------------------------------------------------------------------------------
1 | Bonjour <%= shop.owner.name.givenName %>,
2 |
3 |
4 | Vous trouverez ci-dessous les commandes à préparer pour le <%= shippingWhen %>. La collecte s'effectuera entre 10h30 et 14h00 au plus tard.
5 | <% for(var i=0; i
6 | * [<%= items[i].rank %>, <%= items[i].name.familyName %>] <%= items[i].quantity %>x<%= items[i].title %> (<%= items[i].part %>) *<%= items[i].finalprice.toFixed(2) %>*<% } %>
7 |
8 | N'oubliez-pas d'inscrire le numéro de sac sur l'emballage.
9 | Vous pouvez suivre les commandes ici <%= origin %>/admin/orders
10 | Avec mes meilleurs messages,
11 |
12 | Delphine
13 |
14 | | |/ / (_) |
15 | | ' / __ _ _ __ _| |__ ___ _ _
16 | | < / _` | '__| | '_ \ / _ \| | | |
17 | | . \ (_| | | | | |_) | (_) | |_| |
18 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
19 |
20 | tel : +4179.377.21.13
--------------------------------------------------------------------------------
/emails/order-refund/html.ejs:
--------------------------------------------------------------------------------
1 | <%if (develMode) {%>
2 | TEST -- TEST -- TEST
3 | <% } %>Bonjour <%= order.customer.name.givenName %>,
4 |
5 | Le montant de <%= totalWithFees %> CHF, de votre commande <%= order.oid %> du <%= created %> à bien été remboursé.
6 |
7 |
8 | Avec nos meilleurs messages,
9 |
10 | | |/ / (_) |
11 | | ' / __ _ _ __ _| |__ ___ _ _
12 | | < / _` | '__| | '_ \ / _ \| | | |
13 | | . \ (_| | | | | |_) | (_) | |_| |
14 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
15 |
16 |
17 | ----
18 | vos commandes <%= origin %>/account/orders
19 |
--------------------------------------------------------------------------------
/emails/order-refund/text.ejs:
--------------------------------------------------------------------------------
1 | Bonjour <%= order.customer.name.givenName %>,
2 |
3 | Le montant de <%= totalWithFees %> CHF, de votre commande <%= order.oid %> du <%= created %> à bien été remboursé.
4 | Avec nos meilleurs messages,
5 |
6 | | |/ / (_) |
7 | | ' / __ _ _ __ _| |__ ___ _ _
8 | | < / _` | '__| | '_ \ / _ \| | | |
9 | | . \ (_| | | | | |_) | (_) | |_| |
10 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
11 |
12 |
13 | ----
14 | vos commandes <%= origin %>/account/orders
15 |
--------------------------------------------------------------------------------
/emails/order-reminder/html.ejs:
--------------------------------------------------------------------------------
1 | <%if (develMode) {%>
2 | TEST -- TEST -- TEST
3 | <% } %>Bonjour <%= user.name.givenName %>,
4 |
5 | C'est peut-être le moment de faire ses courses chez vos commerçants préférés?
6 |
7 |
8 | Avec nos meilleurs messages,
9 | L'équipe de Karibou.ch
10 |
11 | ----
12 | Modifiez votre alarme <%= origin %>/account/reminder
13 |
--------------------------------------------------------------------------------
/emails/password/html.ejs:
--------------------------------------------------------------------------------
1 | Bonjour <%= name.givenName %>,
2 |
3 | Votre nouveau mot de passe à été créé avec succès.
4 | utilisateur: <%= email.address %>
5 | mot de passe: <%= password %>
6 | <%= origin %>/login
7 |
8 | A bientôt,
9 |
10 | --
11 | James
12 | de l'équipe Karibou.ch
13 |
--------------------------------------------------------------------------------
/emails/password/text.ejs:
--------------------------------------------------------------------------------
1 | Bonjour <%= name.givenName %>,
2 |
3 | Votre nouveau mot de passe à été créé avec succès.
4 | utilisateur: <%= email.address %>
5 | mot de passe: <%= password %>
6 | <%= origin %>/login
7 |
8 | A bientôt,
9 |
10 | --
11 | James
12 | de l'équipe Karibou.ch
13 |
14 |
--------------------------------------------------------------------------------
/emails/shop-status/html.ejs:
--------------------------------------------------------------------------------
1 | Hello,
2 |
3 | L'utilisateur <%= name.givenName %>, <%= email.address %>
4 | (<%= email.status %>), demande d'activation de boutique:
5 | - <%= origin %>/shop/<%= shop.urlpath %>
6 |
7 |
8 | A bientot,
9 |
10 | --
11 | James
12 | de l'équipe Karibou.ch
13 |
14 |
--------------------------------------------------------------------------------
/emails/shop-status/text.ejs:
--------------------------------------------------------------------------------
1 | Hello,
2 |
3 | L'utilisateur <%= name.givenName %>, <%= email.address %> demande d'activation de boutique:
4 | - <%= origin %>/shop/<%= shop.urlpath %>
5 |
6 |
7 | A bientot,
8 |
9 | --
10 | James
11 | de l'équipe Karibou.ch
12 |
13 |
--------------------------------------------------------------------------------
/emails/simple/html.ejs:
--------------------------------------------------------------------------------
1 | Hi,
2 |
3 | <%- content %>
4 |
5 | A bientot,
6 |
7 | --
8 | Olivier Evalet
9 | Ingénieur chez Karibou.
10 | P:(123) 456-7890
11 |
12 |
--------------------------------------------------------------------------------
/emails/simple/text.ejs:
--------------------------------------------------------------------------------
1 | Hi,
2 |
3 | <%- content %>
4 |
5 | A bientot,
6 |
7 | --
8 | Olivier Evalet
9 | Ingénieur chez Karibou.
10 | P:(123) 456-7890
11 |
12 |
--------------------------------------------------------------------------------
/emails/wallet-new/text.ejs:
--------------------------------------------------------------------------------
1 | <%if (develMode) {%>
2 | TEST -- TEST -- TEST
3 | <% } %>Bonjour <%= user.name.givenName %>,
4 | Vous avez commandé une carte cadeau karibou pour un montant de <%= (wallet.balance/100).toFixed(2) %> fr.
5 | Voici le code de la carte : <%= wallet.card.number %> cette carte est valable juqu'au <%= wallet.card.expiry %>.
6 |
7 | Comment ça marche? Envoyé à la personne de votre choix, un petit mot avec la marche à suivre suivante:
8 | 1. Créer un compte chez karibou.ch, c'est essentiel pour utiliser votre carte cadeau ;)
9 | 2. Pour enregister votre nouvelle carte, allez dans votre compte personnel, et choisissez mes méthodes de paiement.
10 | 3. Ensuite, il suffit de cliquer sur le boutton [utiliser une carte cadeau].
11 | 4. Finalement, enregistrez votre carte avec le numéro suivant <%= wallet.card.number %> . (ce code est valable jusqu'au <%= wallet.card.expiry %>)
12 |
13 | Voilà c'est fait, maintenant vous pouvez faire vos courses pour un montant de <%= (wallet.balance/100).toFixed(2) %> fr chez les commerçants de l'alimentation de Genève.
14 |
15 |
16 | Avec nos meilleurs messages,
17 |
18 | | |/ / (_) |
19 | | ' / __ _ _ __ _| |__ ___ _ _
20 | | < / _` | '__| | '_ \ / _ \| | | |
21 | | . \ (_| | | | | |_) | (_) | |_| |
22 | |_|\_\__,_|_| |_|_.__/ \___/ \__,_|
23 |
24 |
25 | ----
26 | votre compte commercial <%= origin %>/account/wallet
27 |
--------------------------------------------------------------------------------
/karibou.sublime-project:
--------------------------------------------------------------------------------
1 | {
2 | "folders":
3 | [
4 | {
5 | "path": "/home/evaleto/nodejs/git/karibou-api"
6 | }
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/maintain.js:
--------------------------------------------------------------------------------
1 | #!/bin/env node
2 |
3 | //
4 | //
5 | var app = require('./app');
6 | var maintain=require('./app/db.maintain');
7 | //var mongoose=require('mongoose');
8 |
9 |
10 | /** */
11 | var MongoClient = require('mongodb').MongoClient;
12 | MongoClient.connect(config.mongo.name, function(err, db) {
13 | console.time("maintain is done");
14 | maintain.update(db,function(err,log){
15 | if(err){
16 | console.log("ERROR",err)
17 | }
18 | console.timeEnd("maintain is done");
19 | process.exit(1);
20 | });
21 |
22 | });
23 |
24 | /**
25 | mongoose.connection.on('open', function(db) {
26 |
27 | maintain.update(mongoose.connection.db,function(err,log){
28 | console.log("maintain",err,log);
29 | process.exit(1);
30 | });
31 |
32 | });
33 |
34 | */
35 |
--------------------------------------------------------------------------------
/maintain/0001.mongo_script.js:
--------------------------------------------------------------------------------
1 | exports.execute = function(db, script, callback){
2 | return callback(null, "hello world");
3 | }
4 |
--------------------------------------------------------------------------------
/maintain/0002.product_photo_to_object.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Convert all products.photo to products.photo.url");
33 | var logs="", count=0;
34 | var products=db.collection('products');
35 |
36 | products.find( {'photo':{$type:2 } }).toArray(function (err,p) {
37 | if (!p.length){
38 | return callback(null, "0 product have been updated")
39 | }
40 | console.log(script,"migrating "+p.length +" products");
41 | require('async').each(p, function(product, eachcb){
42 | var url=product.photo;
43 | product.photo = {url:url};
44 | products.save(product,function(err){
45 | console.log(err, product.photo)
46 | eachcb(err);
47 | });
48 |
49 | // products.update({_id: product._id}, {$set: {photo: {url:product.photo}}}, {w:1}, function(err) {
50 | // eachcb(err);
51 | // });
52 |
53 | // product.save(function(err){
54 | // assert.ok(typeof product.photo === 'object',"product.photo should be an object {url:string}")
55 | // eachcb(err);
56 | // });
57 | },
58 | function(err){
59 | return callback(err, p.length+" photos on products have been updated");
60 | });
61 | });
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/maintain/0003.shop_options_to_details.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all shop.options and rename it to shop.details
7 | *
8 | * Use case
9 | * 1) How to change the type of a field?
10 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
11 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
12 | * x.bad = new String(x.bad); // convert field to string
13 | * db.foo.save(x);
14 | * });
15 | *
16 | * 2) How to rename a field
17 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
18 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
19 | *
20 | * $type:
21 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
22 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
23 | * Null 10, Regular Expression 11, JavaScript 13,
24 | * Symbol 14, JavaScript (with scope) 15,
25 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
26 | *
27 | */
28 |
29 |
30 | exports.execute = function(db, script, callback){
31 | console.log(script,"Convert all shop.options to shop.details");
32 | var logs="", count=0;
33 | var shops=db.collection('shops');
34 |
35 | shops.find( {'options':{$type:3 } }).toArray(function (err,s) {
36 | if (!s.length){
37 | return callback(null, "0 shop have been updated")
38 | }
39 | console.log(script,"migrating "+s.length +" shops");
40 | shops.update({'options':{$type:3 } }, { $rename: { "options": "details" } }, {multi:true} ,function(err,count){
41 | callback(err, count+" shops have been updated");
42 | })
43 |
44 | });
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/maintain/0004.shop_address_localtion_to_geo.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all shop.options and rename it to shop.details
7 | *
8 | * Use case
9 | * 1) How to change the type of a field?
10 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
11 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
12 | * x.bad = new String(x.bad); // convert field to string
13 | * db.foo.save(x);
14 | * });
15 | *
16 | * 2) How to rename a field
17 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
18 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
19 | *
20 | * $type:
21 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
22 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
23 | * Null 10, Regular Expression 11, JavaScript 13,
24 | * Symbol 14, JavaScript (with scope) 15,
25 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
26 | *
27 | */
28 |
29 |
30 | exports.execute = function(db, script, callback){
31 | var logs="", count=0;
32 | var users=db.collection('users');
33 | callback(null,"nothing todo")
34 | // users.find( {'address.location':{$type:3 } }).toArray(function (err,s) {
35 | // if (!s.length){
36 | // return callback(null, "0 shop have been updated")
37 | // }
38 | // console.log(script,"migrating "+s.length +" users");
39 | // users.update({}, { $rename: { "address.location": "address.geo" } } ,function(err){
40 | // callback(err, s.length+" users have been updated");
41 | // })
42 |
43 | // });
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/maintain/0005.shop_localtion_to_address_location.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all shop.options and rename it to shop.details
7 | *
8 | * Use case
9 | * 1) How to change the type of a field?
10 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
11 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
12 | * x.bad = new String(x.bad); // convert field to string
13 | * db.foo.save(x);
14 | * });
15 | *
16 | * 2) How to rename a field
17 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
18 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
19 | *
20 | * $type:
21 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
22 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
23 | * Null 10, Regular Expression 11, JavaScript 13,
24 | * Symbol 14, JavaScript (with scope) 15,
25 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
26 | *
27 | */
28 |
29 |
30 | exports.execute = function(db, script, callback){
31 | console.log(script,"Convert all shop.location to shop.address.location");
32 | var logs="", count=0;
33 | var shops=db.collection('shops');
34 |
35 | shops.find( {'location':{$type:2 } }).toArray(function (err,s) {
36 | if (!s.length){
37 | return callback(null, "0 shop have been updated")
38 | }
39 | console.log(script,"migrating "+s.length +" shops");
40 | shops.update({'location':{$type:2 } }, { $rename: { "location": "address.location" } }, {multi:true} ,function(err,count){
41 | callback(err, count+" shops have been updated");
42 | })
43 |
44 | });
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/maintain/0006.product_category_is_no_more_an_array.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Convert all products.categories to products.category");
33 | var logs="", count=0;
34 | var products=db.collection('products');
35 |
36 | products.find( {$where : "Array.isArray(this.categories)"}).toArray(function (err,p) {
37 | if (!p.length){
38 | return callback(null, "0 product have been updated")
39 | }
40 | console.log(script,"migrating "+p.length +" products");
41 | require('async').each(p, function(product, eachcb){
42 |
43 | var cat=product.categories[0];
44 | product.categories = cat;
45 | products.save(product,function(err){
46 | console.log(err, product.categories)
47 | eachcb(err);
48 | });
49 |
50 | // products.update({_id: product._id}, {$set: {photo: {url:product.photo}}}, {w:1}, function(err) {
51 | // eachcb(err);
52 | // });
53 |
54 | // product.save(function(err){
55 | // assert.ok(typeof product.photo === 'object',"product.photo should be an object {url:string}")
56 | // eachcb(err);
57 | // });
58 | },
59 | function(err){
60 | return callback(err, p.length+" categories on products have been updated");
61 | });
62 | });
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/maintain/0007.users_address_region_ge_to_geneve.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Convert all user.addresses.region GE => Genève");
33 | var logs="", count=0;
34 | var users=db.collection('users');
35 |
36 |
37 | users.find( {"addresses.region":"GE"}).toArray(function (err,u) {
38 | if (!u.length){
39 | return callback(null, "0 shop have been updated")
40 | }
41 | console.log(script,"updating region addresse: "+u.length );
42 | users.update({"addresses.region":"GE"} , {$set: {"addresses.$.region": "Genève"}}, {multi:true} ,function(err,count){
43 | callback(err, count+" users have been updated");
44 | })
45 |
46 | });
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/maintain/0008.order_drop_unknow_index_ac.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"drop unknow index ac");
33 | var logs="", count=0;
34 | var orders=db.collection('orders');
35 | // orders.getIndexes(function(e,index){
36 | // console.log(e,index)
37 | // })
38 | orders.dropIndex({'ac':1},function(e,idx){
39 | var err;
40 | if(e&&e.errmsg&&e.errmsg.indexOf('find index with key')!=-1){
41 | return callback(null,"ok")
42 | }
43 |
44 | callback(e,idx)
45 | });
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/maintain/0009.users_login_date.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Add user activities (date for login and update) on users");
33 | var logs="", count=0, date=new Date('1972');
34 | var users=db.collection('users');
35 |
36 |
37 | users.find({ logged: { $exists: false}}).toArray(function (err,u) {
38 | if (!u.length){
39 | return callback(null, "0 user have been updated")
40 | }
41 | console.log(script,"updating users activity(logged,updated) : "+u.length );
42 | users.update({ logged: { $exists: false}} , {$set: {logged:date, updated:date}}, {multi:true},function(err){
43 | callback(err, u.length+" users have been updated");
44 | })
45 |
46 | });
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/maintain/0010.orders_close_all_that_are_cancel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Close all orders that are canceled");
33 | var logs="", count=0;
34 | var orders=db.collection('orders');
35 |
36 |
37 | orders.find({'cancel.when':{$exists:true},closed:{$exists:false}}).toArray(function (err,o) {
38 | if (!o.length){
39 | return callback(null, "0 orders have been updated")
40 | }
41 | console.log(script,"updating orders : "+o.length );
42 |
43 | require('async').each(o, function(order, eachcb){
44 |
45 | order.closed=order.cancel.when;
46 | orders.save(order,function(err){
47 | eachcb(err);
48 | });
49 | },
50 | function(err){
51 | return callback(err, o.length+" orders have been updated");
52 | });
53 |
54 |
55 | });
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/maintain/0011.orders_close_all_that_are_failures.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Close all orders that are failure");
33 | var logs="", count=0;
34 | var orders=db.collection('orders');
35 |
36 |
37 | orders.find({'fulfillments.status':'failure',closed:{$exists:false}}).toArray(function (err,o) {
38 | if (!o.length){
39 | return callback(null, "0 orders have been updated")
40 | }
41 | console.log(script,"updating orders : "+o.length );
42 |
43 | require('async').each(o, function(order, eachcb){
44 |
45 | order.closed=Date.now();
46 | orders.save(order,function(err){
47 | eachcb(err);
48 | });
49 | },
50 | function(err){
51 | return callback(err, o.length+" orders have been updated");
52 | });
53 |
54 |
55 | });
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/maintain/0012.users_address_region_has_new_enum.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Convert all user.addresses.region $ => .*GE$");
33 | var logs="", count=0;
34 | var users=db.collection('users');
35 | var tosave=false, errs=[],logs=[];
36 |
37 |
38 | users.find( {"addresses.region":{$not:/GE$/}}).toArray(function (err,u) {
39 | if (!u.length){
40 | return callback(null, "0 user have been updated")
41 | }
42 | console.log(script,"updating region addresse: "+u.length );
43 |
44 | u.forEach(function(user){
45 | tosave=false;
46 | user.addresses.forEach(function(add){
47 | //console.log("user",user.id,add.region,/(Genène|France)/.test(add.region))
48 | if(!/.*(Genève|France)$/.test(add.region)){
49 | add.region=add.region+',GE'
50 | tosave=true;
51 | }
52 | })
53 | if(tosave){
54 | console.log(user)
55 | users.update({id:user.id},user,function(err){
56 | if(errs)errs.push(err);
57 | })
58 | }
59 | })
60 |
61 | callback(errs.join(','), u.length+" users have been updated");
62 |
63 | });
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/maintain/0013.shops_address_region_has_new_enum.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Convert all shop.address.region $ => .*GE$");
33 | var logs="", count=0;
34 | var Shops=db.collection('shops');
35 | var tosave=false, errs=[],logs=[];
36 |
37 |
38 | Shops.find( {"address.region":{$not:/GE$/}}).toArray(function (err,shops) {
39 | if (!shops.length){
40 | return callback(null, "0 shops have been updated")
41 | }
42 | console.log(script,"updating region addresse: "+shops.length );
43 |
44 | shops.forEach(function(shop){
45 | if(!/.*(Genève|France)$/.test(shop.address.region)){
46 | shop.address.region=shop.address.region+',GE'
47 | Shops.update({urlpath:shop.urlpath},shop,function(err){
48 | if(err)errs.push(err);
49 | })
50 |
51 | }
52 |
53 | })
54 |
55 | callback(errs.join(','), shops.length+" shops have been updated");
56 |
57 | });
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/maintain/0014.convert_user_likes_from_object_type_to_sku.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Convert all user likes from Product Object to SKU number");
33 | var logs="", count=0,mapping={};
34 | var Products=db.collection('products');
35 | var Users=db.collection('users');
36 | var tosave=false, errs=[],logs=[];
37 |
38 | // find all
39 | db.collection('products').find({}).toArray(function (err,products) {
40 | products.forEach(function (product) {
41 | mapping[product._id]=product.sku
42 | })
43 |
44 | // object id == 7
45 | Users.find( {"likes":{$type:7}}).toArray(function (err,users) {
46 | if (!users.length){
47 | return callback(null, "0 user have been updated")
48 | }
49 | if(err){
50 | errs.push(err)
51 | }
52 | console.log(script,"updating users likes: "+users.length );
53 |
54 | users.forEach(function(user){
55 | var likes=[];
56 | user.likes.forEach(function (like) {
57 | likes.push(mapping[like]);
58 | });
59 | // update data
60 | user.likes=likes;
61 |
62 | if(user.email)console.log('find:',user.email.address,user.likes);
63 | else console.log('find:',user.id,user.likes);
64 | Users.update({id:user.id},user,function (err) {
65 | if(err)errs.push(err);
66 | })
67 | })
68 |
69 | callback(errs.join(','), users.length+" users likes have been updated");
70 |
71 | });
72 |
73 | });
74 |
75 |
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/maintain/0015.users_payment_rename_issuer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | //
32 | // {
33 | // "alias" : "8ff17caf9b429fa74d6f93a361fa2f8f44891e3ea22b41257857fdcf6be56caa0e0e0e0e",
34 | // "type" : "visa",
35 | // "name" : "oli evalet",
36 | // "number" : "40xxxxxxxxxx1881",
37 | // "csc" : "321",
38 | // "expiry" : "12/2015",
39 | // "updated" : 1413375339775
40 | // }
41 |
42 |
43 | exports.execute = function(db, script, callback){
44 | console.log(script,"Convert all user.payments.type => payments.issuer");
45 | var logs="", count=0;
46 | var Users=db.collection('users');
47 | var tosave=false, errs=[],logs=[];
48 |
49 |
50 | Users.find({'payments.type':{$exists:true}}).toArray(function (err,users) {
51 | if (!users.length){
52 | return callback(null, "0 users have been updated")
53 | }
54 | console.log(script,"updating payment issuer: "+users.length );
55 |
56 | for (var i = users.length - 1; i >= 0; i--) {
57 | users[i].payments.forEach(function (payment) {
58 | payment['issuer']=payment.type;
59 | delete payment.type;
60 | })
61 | Users.update({id:users[i].id},users[i],function (err) {
62 | if(err)errs.push(err);
63 | })
64 | };
65 |
66 |
67 | callback(errs.join(','), users.length+" users have been updated");
68 |
69 | });
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/maintain/0016.product_photo_https_url.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 | var aws={
31 | in:"//karibou-filepicker.s3-website-eu-west-1.amazonaws.com/",
32 | out:"//s3-eu-west-1.amazonaws.com/karibou-filepicker/"
33 | };
34 |
35 | exports.execute = function(db, script, callback){
36 | console.log(script,"Convert all products.photo.url to be https complient");
37 | var logs="", count=0;
38 | var products=db.collection('products');
39 |
40 | products.find( {}).toArray(function (err,p) {
41 | if (!p.length){
42 | return callback(null, "0 product have been updated")
43 | }
44 | console.log(script,"migrating "+p.length +" products");
45 |
46 | //
47 | // convert url
48 | require('async').each(p, function(product, eachcb){
49 | //
50 | if(!product.photo||!product.photo.url){
51 | console.log('WARNING no photo available for product',product.sku)
52 | return eachcb();
53 | }
54 | var url=product.photo.url.split(aws.in);
55 | if(url.length>1){
56 | product.photo.url=aws.out+url[1]
57 | }
58 | console.log('rename',product.photo.url )
59 | products.save(product,function(err){
60 | eachcb(err);
61 | });
62 |
63 | },
64 | function(err){
65 | return callback(err, p.length+" photos on products have been updated");
66 | });
67 | });
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/maintain/0017.category_photo_https_url.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 | var aws={
31 | in:"//karibou-filepicker.s3-website-eu-west-1.amazonaws.com/",
32 | out:"//s3-eu-west-1.amazonaws.com/karibou-filepicker/"
33 | };
34 |
35 | exports.execute = function(db, script, callback){
36 | console.log(script,"Convert all Category.image to be https complient");
37 | var logs="", count=0;
38 | var catgories=db.collection('categories');
39 |
40 | catgories.find( {}).toArray(function (err,cats) {
41 | if (!cats.length){
42 | return callback(null, "0 product have been updated")
43 | }
44 | console.log(script,"migrating "+cats.length +" catgories");
45 |
46 | //
47 | // convert url
48 | require('async').each(cats, function(category, eachcb){
49 | //
50 | if(!category.cover){
51 | console.log('WARNING no photo available for category ',category.name)
52 | return eachcb();
53 | }
54 | var url=category.cover.split(aws.in);
55 | if(url.length>1){
56 | category.cover=aws.out+url[1]
57 | }
58 | console.log('rename ',category.cover )
59 | catgories.save(category,function(err){
60 | eachcb(err);
61 | });
62 |
63 | },
64 | function(err){
65 | return callback(err, cats.length+" photos on catgories have been updated");
66 | });
67 | });
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/maintain/0018.shop_photo_https_url.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 | var aws={
31 | in:"//karibou-filepicker.s3-website-eu-west-1.amazonaws.com/",
32 | out:"//s3-eu-west-1.amazonaws.com/karibou-filepicker/"
33 | };
34 |
35 | exports.execute = function(db, script, callback){
36 | console.log(script,"Convert all Category.image to be https complient");
37 | var logs="", count=0;
38 | var shops=db.collection('shops');
39 |
40 | shops.find({}).toArray(function (err,lst) {
41 | if (!lst.length){
42 | return callback(null, "0 product have been updated")
43 | }
44 | console.log(script,"migrating "+lst.length +" shops");
45 |
46 | //
47 | // convert url
48 | require('async').each(lst, function(shop, eachcb){
49 | //
50 | if(!shop.photo){
51 | console.log('WARNING no photo available for shop ',shop.name)
52 | return eachcb();
53 | }
54 | if(shop.photo.owner) var owner=shop.photo.owner.split(aws.in);
55 | if(shop.photo.bg) var bg=shop.photo.bg.split(aws.in);
56 | if(shop.photo.fg) var fg=shop.photo.fg.split(aws.in);
57 |
58 | if(owner&&owner.length>1){ shop.photo.owner=aws.out+owner[1]; }
59 | if(bg&&bg.length>1){ shop.photo.bg=aws.out+bg[1]; }
60 | if(fg&&fg.length>1){ shop.photo.fg=aws.out+fg[1]; }
61 | console.log('rename ',shop.photo )
62 | shops.save(shop,function(err){
63 | eachcb(err);
64 | });
65 |
66 | },
67 | function(err){
68 | return callback(err, lst.length+" photos on shops have been updated");
69 | });
70 | });
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/maintain/0019.category_photo_to_uploadcare.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | * migrate to uploadcare
29 | * “Uploadcare allowed us to get photo upload and cropping
30 | into our app within hours. More importantly, they are super
31 | responsive with support. We've been running this in production
32 | for months and our users love it.”
33 | Jeff Friesen, CTO SnuggPro
34 |
35 | */
36 |
37 | var http=require('http');
38 |
39 |
40 | exports.execute = function(db, script, callback){
41 | console.log(script,"Convert all Category.image to uploadcare");
42 | var logs="", count=0;
43 | var catgories=db.collection('categories');
44 | var uploadcare=require('./includes/uploadcare')(config.auth.uploadcare.pub, config.auth.uploadcare.pk)
45 |
46 | //
47 | //
48 | // go and upload images
49 | catgories.find( {}).toArray(function (err,cats) {
50 | if (!cats.length){
51 | return callback(null, "0 product have been updated")
52 | }
53 | console.log(script,"migrating "+cats.length +" catgories");
54 |
55 | //
56 | // convert url
57 | require('async').each(cats, function(category, eachcb){
58 | //
59 | if(!category.cover){
60 | console.log('WARNING no photo available for category ',category.name)
61 | return eachcb();
62 | }
63 |
64 |
65 | uploadcare.file.fromUrl(category.cover, function(err,res){
66 | //Res should contain returned file ID
67 | // 'https://ucarecdn.com/'+res.token
68 | if(err){
69 | return eachcb(err)
70 | }
71 | category.cover='//ucarecdn.com/'+res.uuid+'/';
72 | catgories.save(category,function(err){
73 | console.log('uploadcare ',category.cover )
74 | eachcb(err);
75 | });
76 | })
77 |
78 |
79 | },
80 | function(err){
81 | return callback(err, cats.length+" photos on catgories have been updated");
82 | });
83 | });
84 |
85 |
86 |
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/maintain/0020.shop_photo_https_url.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Convert all shops images to uploadcare");
33 | var logs="", count=0;
34 | var shops=db.collection('shops');
35 | var uploadcare=require('./includes/uploadcare')(config.auth.uploadcare.pub, config.auth.uploadcare.pk)
36 |
37 | shops.find({}).toArray(function (err,lst) {
38 | if (!lst.length){
39 | return callback(null, "0 product have been updated")
40 | }
41 | console.log(script,"migrating "+lst.length +" shops");
42 |
43 | //
44 | // convert url
45 | require('async').each(lst, function(shop, eachcb){
46 | //
47 | if(!shop.photo){
48 | console.log('WARNING no photo available for shop ',shop.name)
49 | return eachcb();
50 | }
51 | var series=[];
52 |
53 | if(shop.photo.owner){
54 | series.push(function (seriescb) {
55 | console.log('upload ow',shop.photo.owner)
56 | uploadcare.file.fromUrl(shop.photo.owner, function(err,res){
57 | if(err){return seriescb(err)}
58 | shop.photo.owner='//ucarecdn.com/'+res.uuid+'/';
59 | seriescb();
60 | });
61 | });
62 | }
63 |
64 | if(shop.photo.bg){
65 | series.push(function (seriescb) {
66 | console.log('upload bg',shop.photo.bg)
67 | uploadcare.file.fromUrl(shop.photo.bg, function(err,res){
68 | if(err){return seriescb(err)}
69 | shop.photo.bg='//ucarecdn.com/'+res.uuid+'/';
70 | seriescb();
71 | });
72 | });
73 | }
74 |
75 | if(shop.photo.fg){
76 | series.push(function (seriescb) {
77 | console.log('upload fg',shop.photo.fg)
78 | uploadcare.file.fromUrl(shop.photo.fg, function(err,res){
79 | if(err){return seriescb(err)}
80 | shop.photo.fg='//ucarecdn.com/'+res.uuid+'/';
81 | seriescb();
82 | });
83 | });
84 |
85 | }
86 | require('async').series(series,
87 | function(err, results){
88 | if(err){return eachcb(err);}
89 | shops.save(shop,function(err){
90 | console.log('renamed ',shop.photo )
91 | eachcb(err);
92 | });
93 | });
94 |
95 |
96 | },
97 | function(err){
98 | return callback(err, lst.length+" photos on shops have been updated");
99 | });
100 | });
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/maintain/0021.product_photo_to_uploadcare.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 | exports.execute = function(db, script, callback){
31 | console.log(script,"Convert all products.photo.url to uploadcare");
32 | var logs="", count=0;
33 | var products=db.collection('products');
34 | var uploadcare=require('./includes/uploadcare')(config.auth.uploadcare.pub, config.auth.uploadcare.pk)
35 |
36 | products.find( {}).toArray(function (err,p) {
37 | if (!p.length){
38 | return callback(null, "0 product have been updated")
39 | }
40 | console.log(script,"migrating "+p.length +" products");
41 |
42 | //
43 | // convert url
44 | require('async').each(p, function(product, eachcb){
45 | //
46 | if(!product.photo||!product.photo.url){
47 | console.log('WARNING no photo available for product',product.sku)
48 | return eachcb();
49 | }
50 | if(product.photo.url){
51 | uploadcare.file.fromUrl(product.photo.url, function(err,res){
52 | if(err){return eachcb(err)}
53 | product.photo.url='//ucarecdn.com/'+res.uuid+'/';
54 |
55 | products.save(product,function(err){
56 | console.log('renamed',product.photo.url )
57 | eachcb(err);
58 | });
59 |
60 | });
61 | }
62 |
63 | },
64 | function(err){
65 | return callback(err, p.length+" photos on products have been updated");
66 | });
67 | });
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/maintain/0022.shop_available_weekdays.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all shop.options and rename it to shop.details
7 | *
8 | * Use case
9 | * 1) How to change the type of a field?
10 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
11 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
12 | * x.bad = new String(x.bad); // convert field to string
13 | * db.foo.save(x);
14 | * });
15 | *
16 | * 2) How to rename a field
17 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
18 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
19 | *
20 | * $type:
21 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
22 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
23 | * Null 10, Regular Expression 11, JavaScript 13,
24 | * Symbol 14, JavaScript (with scope) 15,
25 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
26 | *
27 | */
28 |
29 |
30 | exports.execute = function(db, script, callback){
31 | console.log(script,"Make shop.available.weekdays ready");
32 | var logs="", count=0;
33 | var shops=db.collection('shops');
34 |
35 | shops.find({}).toArray(function (err,s) {
36 | if (!s.length){
37 | return callback(null, "0 shop have been updated")
38 | }
39 | console.log(script,"migrating "+s.length +" shops");
40 | shops.update({}, { $set: { "available.weekdays": [2,5] } },{ multi: true } ,function(err,res){
41 | callback(err, s.length+" shops have been updated");
42 | })
43 |
44 | });
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/maintain/0023.shop_account_bm.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all shop.options and rename it to shop.details
7 | *
8 | * Use case
9 | * 1) How to change the type of a field?
10 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
11 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
12 | * x.bad = new String(x.bad); // convert field to string
13 | * db.foo.save(x);
14 | * });
15 | *
16 | * 2) How to rename a field
17 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
18 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
19 | *
20 | * $type:
21 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
22 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
23 | * Null 10, Regular Expression 11, JavaScript 13,
24 | * Symbol 14, JavaScript (with scope) 15,
25 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
26 | *
27 | */
28 |
29 |
30 | exports.execute = function(db, script, callback){
31 | console.log(script,"Make shop.account business model ready");
32 | var logs="", count=0;
33 | var shops=db.collection('shops');
34 |
35 | shops.update({}, { $set: { "account": {fees:.15,updated:Date.now()} } },{ multi: true } ,function(err,count){
36 | callback(err, count+" shops have been updated");
37 | })
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/maintain/0024.orders_add_vendor_bm.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all shop.options and rename it to shop.details
7 | *
8 | * Use case
9 | * 1) How to change the type of a field?
10 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
11 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
12 | * x.bad = new String(x.bad); // convert field to string
13 | * db.foo.save(x);
14 | * });
15 | *
16 | * 2) How to rename a field
17 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
18 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
19 | *
20 | * $type:
21 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
22 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
23 | * Null 10, Regular Expression 11, JavaScript 13,
24 | * Symbol 14, JavaScript (with scope) 15,
25 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
26 | *
27 | */
28 |
29 |
30 | exports.execute = function(db, script, callback){
31 | console.log(script,"Add order.vendors business model default value of 15%");
32 | var logs="", count=0;
33 | var orders=db.collection('orders');
34 |
35 | orders.find({}).toArray(function (err,os) {
36 | if (!os.length){
37 | return callback(null, "0 order have been updated")
38 | }
39 | console.log(script,"migrating "+os.length +" orders");
40 | require('async').each(os, function(order, eachcb){
41 |
42 | //
43 | // update BM on for each vendors
44 | order.vendors.forEach(function (vendor) {
45 | vendor.fees=0.15;
46 | })
47 |
48 | orders.save(order,function(err){
49 | eachcb(err);
50 | });
51 |
52 | },
53 | function(err){
54 | return callback(err, os.length+" orders have been updated");
55 | });
56 | });
57 |
58 | // this is not possible, waiting for $$ operator
59 | // see here https://jira.mongodb.org/browse/SERVER-1243
60 | // orders.update({'vendors.fees':{$ne:true}} , {$set: {"vendors.$$.fees": 0.15}},{multi:true}, function(err,count){
61 | // callback(err, count+" orders have been updated");
62 | // })
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/maintain/0025.orders_add_shipping_fees.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all shop.options and rename it to shop.details
7 | *
8 | * Use case
9 | * 1) How to change the type of a field?
10 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
11 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
12 | * x.bad = new String(x.bad); // convert field to string
13 | * db.foo.save(x);
14 | * });
15 | *
16 | * 2) How to rename a field
17 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
18 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
19 | *
20 | * $type:
21 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
22 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
23 | * Null 10, Regular Expression 11, JavaScript 13,
24 | * Symbol 14, JavaScript (with scope) 15,
25 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
26 | *
27 | */
28 |
29 |
30 | exports.execute = function(db, script, callback){
31 | console.log(script,"Store the shipping cost in order payment");
32 | var logs="", count=0;
33 | var orders=db.collection('orders');
34 |
35 | // this is not possible, waiting for $$ operator
36 | // see here https://jira.mongodb.org/browse/SERVER-1243
37 | orders.update({'payment.fees':{$ne:true}} , {$set: {"payment.fees": {shipping:10}}},{multi:true}, function(err,count){
38 | callback(err, count+" orders have been updated");
39 | })
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/maintain/0026.orders_add_payment_provider.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all shop.options and rename it to shop.details
7 | *
8 | * Use case
9 | * 1) How to change the type of a field?
10 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
11 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
12 | * x.bad = new String(x.bad); // convert field to string
13 | * db.foo.save(x);
14 | * });
15 | *
16 | * 2) How to rename a field
17 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
18 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
19 | *
20 | * $type:
21 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
22 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
23 | * Null 10, Regular Expression 11, JavaScript 13,
24 | * Symbol 14, JavaScript (with scope) 15,
25 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
26 | *
27 | */
28 |
29 |
30 | exports.execute = function(db, script, callback){
31 | console.log(script,"Store the payment provider in orders");
32 | var logs="", count=0;
33 | var orders=db.collection('orders');
34 |
35 | // this is not possible, waiting for $$ operator
36 | // see here https://jira.mongodb.org/browse/SERVER-1243
37 | orders.update({'payment.provider':{$ne:true}} , {$set: {"payment.provider": 'striper'}},{multi:true}, function(err,count){
38 | callback(err, count+" orders have been updated");
39 | })
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/maintain/0027.product_slug_title.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | * find all product where photo is a string
7 | * - convert the field photo:string => photo:{url:string}
8 | *
9 | * Use case
10 | * 1) How to change the type of a field?
11 | * see type here http://docs.mongodb.org/manual/reference/operator/type/#op._S_type
12 | * db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
13 | * x.bad = new String(x.bad); // convert field to string
14 | * db.foo.save(x);
15 | * });
16 | *
17 | * 2) How to rename a field
18 | * db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
19 | * db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
20 | *
21 | * $type:
22 | * Double 1, String 2, Object 3, Array 4, Binary data 5,
23 | * Undefined (deprecated) 6, Object id 7, Boolean 8, Date 9,
24 | * Null 10, Regular Expression 11, JavaScript 13,
25 | * Symbol 14, JavaScript (with scope) 15,
26 | * 32-bit integer 16, Timestamp 17, 64-bit integer 18, Min key 255, Max key 127
27 | *
28 | */
29 |
30 |
31 | exports.execute = function(db, script, callback){
32 | console.log(script,"Create product.slug from products.title ");
33 | var logs="", count=0;
34 | var products=db.collection('products');
35 |
36 | products.find( {slug:{$exists:false}}).toArray(function (err,p) {
37 | if (!p.length){
38 | return callback(null, "0 product have been updated")
39 | }
40 | console.log(script,"migrating "+p.length +" products");
41 |
42 | //
43 | // convert url
44 | require('async').each(p, function(product, eachcb){
45 | //
46 | if(product.slug){
47 | console.log('WARNING slug is available for this product',product.sku)
48 | return eachcb();
49 | }
50 | product.slug=product.title.slug();
51 | console.log('slug:',product.sku,product.slug )
52 | products.save(product,function(err){
53 | eachcb(err);
54 | });
55 |
56 | },
57 | function(err){
58 | return callback(err, p.length+" slug on products have been updated");
59 | });
60 | });
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/maintain/0028.default_activity_for_products.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | *
4 | */
5 |
6 |
7 | exports.execute = function(db, script, callback){
8 | console.log(script,"Init activity for all products");
9 | var logs="", count=0;
10 | var products=db.collection('products'), activity=db.collection('activities');
11 |
12 | products.find( {}).toArray(function (err,p) {
13 | if (!p.length){
14 | return callback(null, "0 product have been updated")
15 | }
16 | console.log(script,"activities for "+p.length +" products");
17 | require('async').each(p, function(product, eachcb){
18 |
19 | var doc={
20 | who:{id:1,email:'evaleto@gmail.com',name:'system'},
21 | what:{type:'Products',key:'sku',id:product.sku+'',action:'create'},
22 | content:{pricing:product.pricing,title:product.title},
23 | when:new Date()
24 | };
25 | activity.save(doc,function(err){
26 | if(err){
27 | console.log('ERROR',product.sku,err)
28 | }
29 | eachcb(err);
30 | });
31 |
32 | },
33 | function(err){
34 | return callback(err, p.length+" activities have been created");
35 | });
36 | });
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/maintain/0030.i18n-documents.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | exports.execute = function(db, script, callback){
4 | console.log(script,"Convert all documents for i18n");
5 | var logs="", count=0;
6 | var documents=db.collection('documents');
7 |
8 | documents.find( {}).toArray(function (err,p) {
9 | if (!p.length){
10 | return callback(null, "0 doc have been updated")
11 | }
12 | console.log(script,"migrating "+p.length +" documents");
13 | require('async').each(p, function(doc, eachcb){
14 |
15 | //
16 | // convert title
17 | if(!doc.title.fr)doc.title={fr:doc.title};
18 |
19 | //
20 | // convert content
21 | if(!doc.content.fr)doc.content={fr:doc.content};
22 |
23 | //
24 | // convert header
25 | if(!doc.header.fr)doc.header={fr:doc.header};
26 |
27 | //
28 | // convert slug
29 | if(!Array.isArray(doc.slug)&&doc.slug)doc.slug=[doc.slug];
30 |
31 | documents.save(doc,function(err){
32 | console.log(err, doc.slug)
33 | eachcb(err);
34 | });
35 | },
36 | function(err){
37 | return callback(err, p.length+" documents have been updated");
38 | });
39 | });
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/maintain/0031.i18n-config.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | exports.execute = function(db, script, callback){
4 | console.log(script,"Convert all configs for i18n");
5 | var logs="", count=0;
6 | var configs=db.collection('configs');
7 |
8 | configs.find( {}).toArray(function (err,p) {
9 | if (!p.length){
10 | return callback(null, "0 conf have been updated")
11 | }
12 | console.log(script,"migrating "+p.length +" configs");
13 | require('async').each(p, function(conf, eachcb){
14 |
15 | //
16 | // convert maintenance.reason
17 | if(!conf.maintenance.reason||!conf.maintenance.reason.fr){
18 | conf.maintenance.reason={fr:conf.maintenance.reason};
19 | }
20 |
21 | //
22 | // convert noshipping
23 | for (var i = conf.noshipping.length - 1; i >= 0; i--) {
24 | if(conf.noshipping[i].reason&&!conf.noshipping[i].reason.fr){
25 | conf.noshipping[i].reason={fr:conf.noshipping[i].reason};
26 | }
27 | };
28 |
29 | if(!conf.menu){
30 | conf.menu=[];
31 | }
32 |
33 | if(!conf.home){
34 | conf.home={};
35 | }
36 |
37 | conf.home.views=[];
38 | conf.home.siteName={};
39 | conf.home.tagLine={h:{},p:{}};
40 | conf.home.about={h:{},p:{}};
41 | conf.home.footer={h:{},p:{}};
42 |
43 |
44 | configs.save(conf,function(err){
45 | console.log(err, conf.slug)
46 | eachcb(err);
47 | });
48 | },
49 | function(err){
50 | return callback(err, p.length+" configs have been updated");
51 | });
52 | });
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/maintain/0032.orders_fees_charge.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Maintain mongo database
3 | * http://docs.mongodb.org/manual/reference/operator/#AdvancedQueries-%24type
4 | *
5 | *
6 | */
7 |
8 |
9 | exports.execute = function(db, script, callback){
10 | console.log(script,"Add order.payment.fees.charge default value of 2.9%");
11 | var logs="", count=0;
12 | var orders=db.collection('orders');
13 |
14 | orders.update({'payment.fees.charge':{$exists:false}}, {$set: {'payment.fees.charge': 0.029}}, { multi: true });
15 |
16 | return callback(0,"orders have been updated");
17 | }
18 |
--------------------------------------------------------------------------------
/models/activities.js:
--------------------------------------------------------------------------------
1 |
2 | var debug = require('debug')('activities')
3 | , bus = require('../app/bus')
4 | , Q = require('q')
5 | , assert = require("assert")
6 | , _ =require('underscore')
7 | , mongoose= require('mongoose')
8 | , Schema = mongoose.Schema
9 | , ObjectId= Schema.Types.ObjectId;
10 |
11 | var EnumAction="create update delete error".split(' ');
12 |
13 |
14 | var Activity = new Schema({
15 | who:{
16 | id:{ type: Number, required: true },
17 | name:{ type: String, required: true },
18 | email:{ type: String, required: true }
19 | },
20 |
21 | what:{
22 | type:{ type: String, required: true },
23 | key:{ type: String, required: true },
24 | id:{ type: String, required: true },
25 | action:{ type: String, required: true, enum:EnumAction }
26 | },
27 |
28 | content:{type:Schema.Types.Mixed, required:true},
29 |
30 | when:{ type: Date, default: Date.now },
31 |
32 | });
33 |
34 |
35 |
36 | //
37 | // create a new activities 'p' for the shop 's'
38 | Activity.statics.create = function(who,what,content,callback){
39 | assert(who);
40 | assert(what);
41 | assert(content);
42 | assert(callback);
43 | var Activities=this, doc={what:what,content:content};
44 |
45 | //
46 | // set user info
47 | doc.who={id:who.id,email:who.email.address,name:who.name.familyName};
48 |
49 |
50 | //
51 | // ready to create one product
52 | var myActivity =new Activities(doc);
53 |
54 | return myActivity.save(callback);
55 | };
56 |
57 |
58 | Activity.statics.findByCrireria = function(criteria, callback){
59 | var query={}, from=new Date(),to;
60 |
61 |
62 | if(criteria.type){
63 | query['what.type']=criteria.type;
64 | }
65 |
66 | if(criteria.month){
67 | from.setDate(1)
68 | from.setMonth(parseInt(criteria.month)-1)
69 | from.setHours(0,0,1,0)
70 | to=new Date(from);
71 | to.setDate(from.daysInMonth())
72 | to.setHours(23,59,59,0)
73 | query['when']={"$gte": from, "$lte": to};
74 | }
75 |
76 | if(criteria.when){
77 | from=new Date(criteria.when);
78 | from.setHours(0,0,1,0);
79 | to=new Date(from);
80 | to.setHours(23,59,59,0)
81 | query['when']={"$gte": from, "$lte": to};
82 | }
83 |
84 | //
85 | // findByUser
86 | if(criteria.uid){
87 | query['who.id']=criteria.uid;
88 | }
89 | if(criteria.email){
90 | query['who.email']=new RegExp('^.*'+criteria.email+'.*$', "i");
91 | }
92 |
93 | //
94 | // findBy Content
95 | if(criteria.what){
96 | query['what.type']=criteria.what;
97 | }
98 |
99 |
100 | if(callback) return this.find(query).exec(callback);
101 | return this.find(query);
102 | };
103 |
104 |
105 |
106 | Activity.set('autoIndex', config.mongo.ensureIndex);
107 | exports.Activities = mongoose.model('Activities', Activity);
108 |
109 |
110 |
--------------------------------------------------------------------------------
/models/db.maintain.js:
--------------------------------------------------------------------------------
1 | var mongoose = require('mongoose')
2 | , Schema = mongoose.Schema
3 | , validate = require('mongoose-validate')
4 | , ObjectId = Schema.ObjectId;
5 |
6 |
7 | var DbMaintain = new Schema({
8 | version: { type: Number, required: false, unique:true},
9 | log: { type: String, required: false},
10 | date: {type:Date, default: Date.now}
11 | });
12 |
13 |
14 | // a new DbMaintain is only created if there is not already an existing entry
15 | DbMaintain.statics.save = function(maintain, callback){
16 | var Maintain = this.model('DbMaintain');
17 | var dbm = Maintain(maintain);
18 | dbm.save(function (err, doc){
19 | return callback(err,doc);
20 | });
21 | };
22 |
23 |
24 | DbMaintain.statics.findAll = function(callback){
25 | this.model('DbMaintain').find('{}', function(err, maintain){
26 | return callback(err, maintain);
27 | });
28 | };
29 |
30 |
31 | DbMaintain.statics.findLatestVersion = function(callback){
32 | var Maintain=this.model('DbMaintain');
33 | Maintain.find('{}', 'version', {limit: 1, sort:{_id:-1}}, function(err, versionColl){
34 | var version = (versionColl[0])?(versionColl[0].version):(0);
35 | return callback(err, version);
36 | });
37 | };
38 |
39 | DbMaintain.set('autoIndex', config.mongo.ensureIndex);
40 | module.exports = mongoose.model('DbMaintain', DbMaintain);
41 |
--------------------------------------------------------------------------------
/models/sequences.js:
--------------------------------------------------------------------------------
1 |
2 | var debug = require('debug')('sequences');
3 |
4 | var mongoose = require('mongoose')
5 | , Schema = mongoose.Schema
6 | , ObjectId = Schema.ObjectId;
7 |
8 |
9 | //
10 | // wrap a request to a simple queuing system.
11 | // This should help to avoid race condition on product
12 | var queue=require('../app/queue')(1,true);
13 | var queued=function(f){
14 | return function(req,res){
15 | queue.defer(f,req,res)
16 | }
17 | }
18 |
19 |
20 |
21 | var Sequences = new Schema({
22 | name:{type:String, unique:true},
23 | seq:{type:Number,min:100000, default:1000000}
24 | });
25 |
26 | //
27 | Sequences.statics.initNumber = function(name,value){
28 | var init_Sequences={
29 | sku:1000000,
30 | oid:2000000,
31 | uid:8000000
32 | }
33 | if(!init_Sequences[name]){
34 | init_Sequences[name]=value;
35 | }
36 |
37 | return init_Sequences[name];
38 | };
39 |
40 |
41 | //
42 | // SEQUENCES API
43 |
44 |
45 | Sequences.statics.next = function(name, start, callback){
46 | var promise = new mongoose.Promise;
47 | var Sequences=this.model('Sequences');
48 | var newSeq;
49 | if(typeof start === 'function'){
50 | callback=start;
51 | start=this.initNumber(name,10000000);
52 | }
53 |
54 | //
55 | // attach callback to promise
56 | if(callback){
57 | promise.addBack(callback);
58 | }
59 |
60 | // FIXME race condition here : ,{'$setOnInsert':{name:name,seq:start},{upsert:false}
61 | Sequences.findOneAndUpdate({name:name},{$inc: {seq:1}}, {new:true }, function(err,counter){
62 | if(err){
63 | return promise.reject(err);
64 | }
65 | if(counter){
66 | return promise.resolve(null,counter.seq);
67 | // return callback(err,counter.seq);
68 | }
69 | new Sequences({name:name,seq:start}).save(function(err,n){
70 | return promise.resolve(null,n.seq);
71 | // callback(err,n.seq);
72 | });
73 | });
74 | return promise;
75 | };
76 |
77 |
78 |
79 | // simple wrapper for SKU
80 | Sequences.statics.nextSku = function( callback){
81 | return this.model('Sequences').next("sku",this.initNumber('sku'),callback);
82 | };
83 |
84 | // simple wrapper for Order ID
85 | Sequences.statics.nextOrder = function( callback){
86 | return this.model('Sequences').next("oid",this.initNumber('oid'),callback);
87 | };
88 |
89 | // simple wrapper for Order ID
90 | Sequences.statics.nextUser = function( callback){
91 | return this.model('Sequences').next("uid",this.initNumber('uid'),callback);
92 | };
93 |
94 | Sequences.set('autoIndex', config.mongo.ensureIndex);
95 | module.exports =mongoose.model('Sequences', Sequences);
96 |
97 |
98 |
--------------------------------------------------------------------------------
/newrelic.js:
--------------------------------------------------------------------------------
1 | /**
2 | * New Relic agent configuration.
3 | *
4 | * See lib/config.defaults.js in the agent distribution for a more complete
5 | * description of configuration variables and their potential values.
6 | */
7 | exports.config = {
8 | /**
9 | * Array of application names.
10 | */
11 | app_name : ['karibou-api'],
12 | /**
13 | * Your New Relic license key.
14 | */
15 | license_key : process.env.MEWRELIC_KEY,
16 | logging : {
17 | /**
18 | * Level at which to log. 'trace' is most useful to New Relic when diagnosing
19 | * issues with the agent, 'info' and higher will impose the least overhead on
20 | * production applications.
21 | */
22 | level : 'trace'
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "karibou-api",
3 | "description": "Karibou.ch is an opensource project aim to help the creation of an online community marketplace for food distribution",
4 | "version": "1.2.0",
5 | "private": false,
6 | "engines": {
7 | "node": "4.2.x",
8 | "npm": "3.5.x"
9 | },
10 | "dependencies": {
11 | "appdynamics": "^4.2.3",
12 | "async": "2.x",
13 | "body-parser": "^1.14.1",
14 | "compression": "^1.6.0",
15 | "connect-mongo": "1.x",
16 | "cookie-parser": "1.x",
17 | "cron": "^1.1.0",
18 | "debug": "2.x",
19 | "ejs": "2.x",
20 | "email-templates": "2.x",
21 | "errorhandler": "^1.4.2",
22 | "express": "4.x",
23 | "express-csv": "^0.6.0",
24 | "express-session": "1.x",
25 | "fnv-plus": "1.x",
26 | "helmet": "3.x",
27 | "i18n-2": "0.x",
28 | "jade": "1.x",
29 | "karibou-wallet": "0.x",
30 | "lru-cache": "^4.0.0",
31 | "mailchimp": "1.x",
32 | "method-override": "2.x",
33 | "moment": "2.x",
34 | "mongodb": "2.x",
35 | "mongoose": "4.x",
36 | "mongoose-error-helper": "0.x",
37 | "mongoose-validate": "x",
38 | "morgan": "1.x",
39 | "newrelic": "1.x",
40 | "node-postfinance": "0.x",
41 | "nodemailer": "1.x",
42 | "passport": "0.x",
43 | "passport-google-oauth": "1.x",
44 | "passport-local": "1.x",
45 | "passport-twitter": "1.x",
46 | "password-generator": "2.x",
47 | "q": "1.4.x",
48 | "queue-async": "1.x",
49 | "remarkable": "1.x",
50 | "serve-favicon": "2.x",
51 | "sitemap": "1.x",
52 | "stripe": "3.7.x",
53 | "underscore": "1.x",
54 | "validator": "3.x"
55 | },
56 | "devDependencies": {
57 | "mocha": "3.x",
58 | "pow-mongoose-fixtures": "x",
59 | "should": "6.x",
60 | "should-http": "0.x",
61 | "supertest": "2.x"
62 | },
63 | "scripts": {
64 | "start": "node app.js",
65 | "test": "./node_modules/.bin/mocha test",
66 | "maintain": "node maintain.js"
67 | },
68 | "main": "app.js",
69 | "subdomain": "karibou-api"
70 | }
71 |
--------------------------------------------------------------------------------
/public/css/style.css:
--------------------------------------------------------------------------------
1 | /* Space out content a bit */
2 | body {
3 | padding-top: 20px;
4 | padding-bottom: 20px;
5 | font-size: 18px;
6 | }
7 |
8 | /* Everything but the jumbotron gets side spacing for mobile first views */
9 | .header,
10 | .marketing,
11 | .footer {
12 | padding-right: 15px;
13 | padding-left: 15px;
14 | }
15 |
16 | /* Custom page header */
17 | .header {
18 | padding-bottom: 20px;
19 | border-bottom: 1px solid #e5e5e5;
20 | }
21 | /* Make the masthead heading the same height as the navigation */
22 | .header h3 {
23 | margin-top: 0;
24 | margin-bottom: 0;
25 | line-height: 40px;
26 | }
27 |
28 | /* Custom page footer */
29 | .footer {
30 | padding-top: 19px;
31 | color: #777;
32 | border-top: 1px solid #e5e5e5;
33 | }
34 |
35 | .list-group-item{
36 | padding: 20px 15px;
37 | }
38 |
39 | /* Customize container */
40 | @media (min-width: 768px) {
41 | .container {
42 | max-width: 730px;
43 | }
44 |
45 | .list-group-item{
46 | padding: 10px 15px;
47 | }
48 | }
49 | .container-narrow > hr {
50 | margin: 30px 0;
51 | }
52 |
53 | /* Main marketing message and sign up button */
54 | .jumbotron {
55 | text-align: center;
56 | border-bottom: 1px solid #e5e5e5;
57 | }
58 | .jumbotron .btn {
59 | padding: 14px 24px;
60 | font-size: 21px;
61 | }
62 |
63 | /* Supporting marketing content */
64 | .marketing {
65 | margin: 40px 0;
66 | }
67 | .marketing p + h4 {
68 | margin-top: 28px;
69 | }
70 |
71 | /* Responsive: Portrait tablets and up */
72 | @media screen and (min-width: 768px) {
73 | /* Remove the padding we set earlier */
74 | .header,
75 | .marketing,
76 | .footer {
77 | padding-right: 0;
78 | padding-left: 0;
79 | }
80 | /* Space out the masthead */
81 | .header {
82 | margin-bottom: 30px;
83 | }
84 | /* Remove the bottom border on the jumbotron for visual effect */
85 | .jumbotron {
86 | border-bottom: 0;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/public/img/anais.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evaletolab/karibou-api/c02cef6e3f75123a188e197e20c3e4ae5c1c0c4c/public/img/anais.jpg
--------------------------------------------------------------------------------
/public/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evaletolab/karibou-api/c02cef6e3f75123a188e197e20c3e4ae5c1c0c4c/public/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/public/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evaletolab/karibou-api/c02cef6e3f75123a188e197e20c3e4ae5c1c0c4c/public/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/public/img/hello-home.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evaletolab/karibou-api/c02cef6e3f75123a188e197e20c3e4ae5c1c0c4c/public/img/hello-home.jpg
--------------------------------------------------------------------------------
/public/img/karibou.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evaletolab/karibou-api/c02cef6e3f75123a188e197e20c3e4ae5c1c0c4c/public/img/karibou.jpg
--------------------------------------------------------------------------------
/script/node-continuous.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #
4 | #read params: branch port
5 | [ -z "$2" ] && PORT=3000 || PORT=$2
6 | [ -z "$1" ] && {
7 | echo "usage:$0 "
8 | exit 1
9 | }
10 | #
11 | # check root directory
12 | [ -f app.js ] || {
13 | echo "wrong root directory"
14 | exit 1
15 | }
16 | sleep 2;
17 | echo "#git pull origin $1"
18 | git pull origin $1
19 | npm install
20 |
21 |
22 | echo "#restart server $1"
23 | #nohup bash -c 'sleep 1;node app >> $HOME/www/logs/node-kariboo.logs'&
24 | #fuser -k $PORT/tcp;
25 | #forever start --watchIgnore "*newrelic*" --spinSleepTime 10000 -f -w -o $HOME/www/logs/node-kariboo.logs app
--------------------------------------------------------------------------------
/test/api.category.find.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 | var data = dbtools.fixtures(["Users.js","Categories.js","Shops.js",'Products.js']);
8 |
9 |
10 | describe("api.categories", function(){
11 | var request= require('supertest');
12 | var _=require('underscore');
13 |
14 | var cookie;
15 |
16 | before(function(done){
17 | dbtools.clean(function(e){
18 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Products.js"],db,function(err){
19 | should.not.exist(err);
20 | done();
21 | });
22 | });
23 | });
24 |
25 |
26 | after(function(done){
27 | dbtools.clean(function(){
28 | done();
29 | });
30 | });
31 |
32 |
33 |
34 |
35 | it('GET /v1/category?stats=true should return category usedBy ',function(done){
36 | request(app)
37 | .get('/v1/category?stats=true')
38 | .end(function(err, res){
39 | res.should.have.status(200);
40 | res.body.forEach(function(c){
41 | should.exist(c.usedBy)
42 | })
43 | done();
44 | });
45 | });
46 | });
47 |
48 |
--------------------------------------------------------------------------------
/test/api.orders.report.js:
--------------------------------------------------------------------------------
1 | var app = require("../app");
2 |
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 | var _ = require("underscore");
8 | var request= require('supertest');
9 | var data = dbtools.fixtures(["Users.js","Categories.js","Orders.find.js"]),
10 | Orders=db.model('Orders');
11 |
12 | describe("api.orders.find", function(){
13 | before(function(done){
14 |
15 | dbtools.clean(function(e){
16 | dbtools.load(["../fixtures/Users.js","../fixtures/Orders.report.js"],db,function(err){
17 | should.not.exist(err);
18 |
19 | // Orders.printInfo()
20 | // Orders.find({}).exec(function(e,os){
21 | // os.forEach(function(o){o.print()})
22 | // })
23 |
24 | done();
25 | });
26 | });
27 | });
28 |
29 |
30 | after(function(done){
31 | dbtools.clean(function(){
32 | done();
33 | });
34 | });
35 |
36 | //
37 | // keep session
38 | var cookie;
39 |
40 | it("login",function(done){
41 | request(app)
42 | .post('/login')
43 | .send({ email: "evaleto@gmail.com", password:'password',provider:'local' })
44 | .end(function(e,res){
45 | should.not.exist(e)
46 | cookie = res.headers['set-cookie'];
47 | done()
48 | });
49 | })
50 |
51 | it('GET /v1/orders should return 401 for anonymous',function(done){
52 | request(app)
53 | .get('/v1/orders')
54 | .expect(401,done);
55 | });
56 |
57 |
58 | it('GET /v1/orders/invoices/shops/12/2014 list all open orders for admin',function(done){
59 | request(app)
60 | .get('/v1/orders/invoices/shops/12/2014')
61 | .set('cookie', cookie)
62 | .expect(200,function(err,res){
63 | should.not.exist(err)
64 | //res.body.length.should.equal(3)
65 | done()
66 | });
67 | });
68 |
69 |
70 | it('GET /v1/orders/invoices/shops/12/2014?shops=crocorient,les-fromages-de-gaetan list all open orders for admin',function(done){
71 | request(app)
72 | .get('/v1/orders/invoices/shops/12/2014?shops=crocorient,les-fromages-de-gaetan')
73 | .set('cookie', cookie)
74 | .expect(200,function(err,res){
75 | should.not.exist(err)
76 | done()
77 | });
78 | });
79 |
80 | it('GET /v1/orders/invoices/shops/12/2014 list all open orders for admin',function(done){
81 | request(app)
82 | .get('/v1/orders/invoices/shops/12/2014')
83 | .expect(401,function(err,res){
84 | should.not.exist(err)
85 | //res.body.length.should.equal(3)
86 | done()
87 | });
88 | });
89 |
90 |
91 |
92 |
93 | });
94 |
95 |
--------------------------------------------------------------------------------
/test/api.products.find.sort.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 | var data = dbtools.fixtures(["Users.js","Categories.js","Shops.js",'Products.more.js']);
8 |
9 | describe("DEPRECATED api.products.find.sort", function(){
10 | var request= require('supertest');
11 |
12 | var _=require('underscore');
13 |
14 |
15 | before(function(done){
16 | dbtools.clean(function(e){
17 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Shops.js","../fixtures/Products.sort.js"],db,function(err){
18 | should.not.exist(err);
19 | done();
20 | });
21 | });
22 | });
23 |
24 | after(function(done){
25 | dbtools.clean(function(){
26 | done();
27 | });
28 | });
29 |
30 | /** SORTING AND GROUPING */
31 | it.skip("GET 200,/v1/products?sort=categories.weight", function(done){
32 | request(app)
33 | .get("/v1/products?sort=categories.weight")
34 | .expect('Content-Type', /json/)
35 | .end(function(err, res){
36 | res.should.have.status(200);
37 | var w=-1;
38 | res.body[0].vendor.should.be.an.instanceOf(Object)
39 | res.body.forEach(function(p){
40 | p.categories.weight.should.be.above(w)
41 | w=p.categories.weight;
42 | });
43 | done();
44 | });
45 | });
46 |
47 | it.skip("GET 200,/v1/products?sort=categories.name", function(done){
48 | request(app)
49 | .get("/v1/products?sort=categories.name")
50 | .expect('Content-Type', /json/)
51 | .end(function(err, res){
52 | res.should.have.status(200);
53 | n='';
54 | res.body[0].vendor.should.be.an.instanceOf(Object)
55 | res.body.forEach(function(p){
56 | p.categories.name.should.be.above(n)
57 | n=p.categories.name;
58 | });
59 | done();
60 | });
61 | });
62 |
63 | it.skip("GET 200,/v1/products?group=categories.name&sort=categories.name", function(done){
64 | request(app)
65 | .get("/v1/products?group=categories.name&sort=categories.name")
66 | .expect('Content-Type', /json/)
67 | .end(function(err, res){
68 | res.should.have.status(200);
69 | var n='';
70 | Object.keys(res.body).forEach(function(k){
71 | k.should.be.above(n);
72 | n=k;
73 | });
74 |
75 | //console.dir(res.body)
76 | done();
77 | });
78 | });
79 |
80 | });
81 |
82 |
--------------------------------------------------------------------------------
/test/api.products.status.find.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 | var data = dbtools.fixtures(["Users.js","Categories.js","Shops.js",'Products.more.js']);
8 |
9 | describe("api.products.find.status", function(){
10 | var request= require('supertest');
11 | var _=require('underscore');
12 |
13 | var admin;
14 |
15 |
16 | before(function(done){
17 | dbtools.clean(function(e){
18 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Shops.js","../fixtures/Products.more.js"],db,function(err){
19 | should.not.exist(err);
20 | done();
21 | });
22 | });
23 | });
24 |
25 | after(function(done){
26 | dbtools.clean(function(){
27 | done();
28 | });
29 | });
30 |
31 | // user (_id:12345, email:gluck)
32 | // 2products ->shop[0](un-autre-shop, id:0004, status:true, owner:gluck)
33 | // 1product ->shop[1](mon-shop, id:0005, status:false, owner:gmail)
34 | // 0product ->shop[2](invalid-shop, id:0006, status:Date , owner:gluck)
35 | it('user.admin /login return 200',function(done){
36 | request(app)
37 | .post('/login')
38 | .send({ email: "evaleto@gmail.com", password:'password', provider:'local' })
39 | .end(function(err,res){
40 | res.should.have.status(200);
41 | admin = res.headers['set-cookie'];
42 | done();
43 | });
44 | });
45 |
46 | it('Change user status to FALSE /v1/users/:id/status should return 200 for admin only',function(done){
47 | request(app)
48 | .post('/v1/users/12345/status')
49 | .set('cookie', admin)
50 | .send({status:false})
51 | .end(function(err,res){
52 | res.should.have.status(200);
53 | res.body.status.should.equal(false)
54 | done();
55 | });
56 | });
57 |
58 | it("GET 200,/v1/shops/un-autre-shop/products/what-ever-filters should return 0 product", function(done){
59 | request(app)
60 | .get("/v1/shops/un-autre-shop/products/category/"+data.Categories[3].slug+"/details/bio+ogm+gluten")
61 | .end(function(err, res){
62 | res.should.have.status(200);
63 | // user gluck status=false => shop.status=false => products(gluck).size=0
64 | res.body.length.should.equal(0)
65 | done();
66 | });
67 | });
68 |
69 | it("GET 200,/v1/shops/un-autre-shop/products should return 0 product", function(done){
70 | request(app)
71 | .get("/v1/shops/un-autre-shop/products")
72 | .end(function(err, res){
73 | //console.log(res.body)
74 | res.should.have.status(200);
75 | // user gluck status=false => shop.status=false => products(gluck).size=0
76 | res.body.length.should.equal(0)
77 | done();
78 | });
79 | });
80 |
81 |
82 | it('users.post status FALSE /v1/users/:id/status should return 200 ',function(done){
83 | request(app)
84 | .post('/v1/users/12345/status')
85 | .set('cookie', admin)
86 | .send({status:true})
87 | .end(function(err,res){
88 | res.should.have.status(200);
89 | res.body.status.should.equal(true)
90 | done();
91 | });
92 | });
93 |
94 |
95 | });
96 |
97 |
--------------------------------------------------------------------------------
/test/api.seo.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 |
8 |
9 | describe("api.categories", function(){
10 | var request= require('supertest');
11 |
12 |
13 | before(function(done){
14 |
15 | dbtools.clean(function(e){
16 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Shops.js","../fixtures/Products.more.js"],db,function(err){
17 | should.not.exist(err);
18 |
19 | // Orders.printInfo()
20 | // Orders.find({}).exec(function(e,os){
21 | // os.forEach(function(o){o.print()})
22 | // })
23 |
24 | done();
25 | });
26 | });
27 | });
28 |
29 |
30 | after(function(done){
31 | dbtools.clean(function(e){
32 | done()
33 | });
34 | });
35 |
36 |
37 |
38 | it('GET /seo/products/category/poissons',function(done){
39 | request(app)
40 | .get('/seo/products/category/poissons')
41 | .expect(200,done);
42 |
43 | });
44 |
45 | it('GET /seo/products',function(done){
46 | request(app)
47 | .get('/seo/products')
48 | .expect(200,done);
49 | });
50 |
51 |
52 | it('GET /seo/',function(done){
53 | request(app)
54 | .get('/seo/')
55 | .expect(200,done);
56 | });
57 |
58 | });
59 |
60 |
--------------------------------------------------------------------------------
/test/api.shops.admin.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 | var data = dbtools.fixtures(["Users.js","Categories.js","Shops.js"]);
8 |
9 |
10 |
11 | describe("api.shops", function(){
12 | var request= require('supertest');
13 |
14 | var _=require('underscore');
15 |
16 | var cookie;
17 |
18 |
19 | before(function(done){
20 | dbtools.clean(function(e){
21 | dbtools.load(["../fixtures/Users.js","../fixtures/Shops.js"],db,function(err){
22 | should.not.exist(err);
23 | done();
24 | });
25 | });
26 | });
27 |
28 | after(function(done){
29 | dbtools.clean(function(){
30 | done();
31 | });
32 | });
33 |
34 |
35 |
36 |
37 | it('GET /v1/shops/this-shop-doesnt-exist should return 400',function(done){
38 | request(app)
39 | .get('/v1/shops/this-shop-doesnt-exist')
40 | .expect(400,done);
41 | });
42 |
43 | it('POST /v1/shops/un-autre-shop should return 401 (you are anonymous)',function(done){
44 | request(app)
45 | .post('/v1/shops/un-autre-shop')
46 | .expect(401,done);
47 | });
48 |
49 |
50 | it('POST /login should return 200 ',function(done){
51 | request(app)
52 | .post('/login')
53 | .send({ email: "evaleto@gmail.com", password:'password', provider:'local' })
54 | .end(function(err,res){
55 | res.should.have.status(200);
56 | res.body.roles.should.containEql('admin');
57 | cookie = res.headers['set-cookie'];
58 | done();
59 | });
60 | });
61 |
62 | it('GET /v1/shops/un-autre-shop should return 200 (SHOW ACCOUNT FEE)',function(done){
63 | request(app)
64 | .get('/v1/shops/un-autre-shop')
65 | .set('cookie', cookie)
66 | .end(function(err,res){
67 | res.should.have.status(200);
68 | should.exist(res.body.account.fees)
69 | done();
70 | });
71 | });
72 |
73 | it('GET /v1/shops/un-autre-shop should return 200 (HIDE ACCOUNT FEE)',function(done){
74 | request(app)
75 | .get('/v1/shops/un-autre-shop')
76 | .end(function(err,res){
77 | res.should.have.status(200);
78 | should.not.exist(res.body.account.fees)
79 | done();
80 | });
81 | });
82 |
83 | it('POST /v1/shops/un-autre-shop should return 200 (you are admin)',function(done){
84 | var s=data.Shops[0]
85 | request(app)
86 | .post('/v1/shops/un-autre-shop')
87 | .send(s)
88 | .set('cookie', cookie)
89 | .end(function(err,res){
90 | res.should.have.status(200);
91 | should.exist(res.body.account.fees)
92 | done();
93 | });
94 | });
95 |
96 | it.skip('POST /v1/shops/un-autre-shop should return 200 (you are owner)',function(done){
97 | var s=data.Shops[0]
98 | request(app)
99 | .post('/v1/shops/un-autre-shop')
100 | .send(s)
101 | .set('cookie', cookie)
102 | .end(function(err,res){
103 | res.should.have.status(200);
104 | should.not.exist(res.body.account.fees)
105 | done();
106 | });
107 | });
108 |
109 | it('GET /v1/users/me should return 200',function(done){
110 | request(app)
111 | .get('/v1/users/me')
112 | .set('cookie', cookie)
113 | .expect(200,done);
114 |
115 | });
116 |
117 | });
118 |
119 |
--------------------------------------------------------------------------------
/test/api.users.likes.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 | var data = dbtools.fixtures(["Users.js","Categories.js","Shops.js",'Products.js']);
8 |
9 |
10 | describe("api.users.likes", function(){
11 | var request= require('supertest');
12 |
13 | var _=require('underscore');
14 |
15 | var cookie, user;
16 |
17 | before(function(done){
18 | dbtools.clean(function(e){
19 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Shops.js","../fixtures/Products.js"],db,function(err){
20 | should.not.exist(err);
21 | done();
22 | });
23 | });
24 | });
25 |
26 |
27 | after(function(done){
28 | dbtools.clean(function(){
29 | done();
30 | });
31 | });
32 |
33 |
34 |
35 |
36 | it('POST /login should return 200 ',function(done){
37 | request(app)
38 | .post('/login')
39 | .send({ email: "evaleto@gmail.com", password:'password', provider:'local' })
40 | .end(function(err,res){
41 | res.should.have.status(200);
42 | res.body.roles.should.containEql('admin');
43 | cookie = res.headers['set-cookie'];
44 | user=res.body;
45 | done();
46 | });
47 | });
48 |
49 |
50 | it('GET /v1/users/me should return 200',function(done){
51 | request(app)
52 | .get('/v1/users/me')
53 | .set('cookie', cookie)
54 | .end(function(err,res){
55 | res.should.have.status(200);
56 | res.body.id.should.equal(user.id)
57 | done()
58 | });
59 |
60 | });
61 |
62 | it('user like wrong product should return 400',function(done){
63 | request(app)
64 | .post('/v1/users/'+user.id+'/like/01234567')
65 | .set('cookie', cookie)
66 | .end(function(err,res){
67 | res.should.have.status(400);
68 | done()
69 | });
70 | });
71 |
72 | it('user like /v1/users/me/like/'+data.Products[0].sku+' should return 200',function(done){
73 | request(app)
74 | .post('/v1/users/'+user.id+'/like/'+data.Products[0].sku)
75 | .set('cookie', cookie)
76 | .end(function(err,res){
77 | res.should.have.status(200);
78 | res.body.likes.length.should.equal(1)
79 | res.body.likes[0].should.equal(data.Products[0].sku)
80 | done()
81 | });
82 | });
83 |
84 | it('GET /v1/users/me should return 1 like 200',function(done){
85 | request(app)
86 | .get('/v1/users/me')
87 | .set('cookie', cookie)
88 | .end(function(err,res){
89 | res.should.have.status(200);
90 | // console.log(res.body.likes)
91 | res.body.likes.length.should.equal(1)
92 | res.body.likes[0].should.equal(data.Products[0].sku)
93 | done()
94 | });
95 |
96 | });
97 |
98 |
99 | it('user like /v1/users/me/like/'+data.Products[0].sku+' should return 200',function(done){
100 | request(app)
101 | .post('/v1/users/'+user.id+'/like/'+data.Products[0].sku)
102 | .set('cookie', cookie)
103 | .end(function(err,res){
104 | res.should.have.status(200);
105 | res.body.likes.length.should.equal(0)
106 | done()
107 | });
108 | });
109 |
110 |
111 |
112 | });
113 |
114 |
--------------------------------------------------------------------------------
/test/api.users.payment.webhook.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 | var data = dbtools.fixtures(["Users.js"]);
8 |
9 | //http://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
10 | describe("api.users.payment.postfinance.webhook", function(){
11 | var request= require('supertest');
12 |
13 | var _=require('underscore');
14 |
15 | var cookie, user;
16 |
17 | var pspWebhook={
18 | orderID: 'AS1423152577442',
19 | currency: 'CHF',
20 | amount: '1',
21 | PM: 'PostFinance Card',
22 | ACCEPTANCE: 'test123',
23 | STATUS: '5',
24 | CARDNO: '**-XXXX-81',
25 | ALIAS: '2091529620513003',
26 | ED: '0719',
27 | CN: 'test1 test1',
28 | TRXDATE: '02/05/15',
29 | PAYID: '39152967',
30 | NCERROR: '0',
31 | BRAND: 'PostFinance Card',
32 | IPCTY: 'CH',
33 | CCCTY: '99',
34 | ECI: '7',
35 | CVCCheck: 'NO',
36 | AAVCheck: 'NO',
37 | VC: '',
38 | AAVADDRESS: 'NO',
39 | AAVNAME: 'NO',
40 | AAVMAIL: 'NO',
41 | IP: '84.227.169.49',
42 | createAlias: 'true',
43 | user: '1279482741765243',
44 | SHASIGN: '5FF339B3F8EEFBB976C0249BD74FD156287BDA3D5A5E99FC1858EB880B1051EE'
45 | }
46 |
47 | //378282246310005
48 |
49 |
50 | before(function(done){
51 | dbtools.clean(function(e){
52 | dbtools.load(["../fixtures/Users.js"],db,function(err){
53 | should.not.exist(err);
54 | done();
55 | });
56 | });
57 | });
58 |
59 |
60 | after(function(done){
61 | dbtools.clean(function(){
62 | done();
63 | });
64 | });
65 |
66 |
67 |
68 |
69 |
70 |
71 | it.skip('PSP webhook create payment for postfinance card',function(done){
72 | request(app)
73 | .post('/v1/psp/qawsedr/webhook')
74 | .send(pspWebhook)
75 | .end(function(err,res){
76 | res.should.have.status(200);
77 | db.model('Users').findOne({id: pspWebhook.user}, function(err,user){
78 | user.payments[0].alias.should.equal(pspWebhook.ALIAS.crypt())
79 | user.payments[0].type.should.equal(pspWebhook.BRAND.toLowerCase())
80 | user.payments[0].name.should.equal(pspWebhook.CN)
81 | user.payments[0].number.should.equal(pspWebhook.CARDNO)
82 | user.payments[0].expiry.should.equal('7/2019')
83 | done()
84 | })
85 | });
86 | });
87 |
88 | it.skip('second PSP webhook got error payment already exist',function(done){
89 | request(app)
90 | .post('/v1/psp/qawsedr/webhook')
91 | .send(pspWebhook)
92 | .end(function(err,res){
93 | res.should.have.status(200);
94 | db.model('Users').findOne({id: pspWebhook.user}, function(err,user){
95 | user.payments.length.should.equal(1)
96 | done()
97 | });
98 | });
99 | });
100 |
101 | });
102 |
--------------------------------------------------------------------------------
/test/api.users.phones.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 | var data = dbtools.fixtures(["Users.js","Categories.js","Shops.js",'Products.js']);
8 |
9 |
10 | describe("api.users.phones", function(){
11 | var request= require('supertest');
12 |
13 | var _=require('underscore');
14 |
15 | var cookie, user;
16 |
17 | before(function(done){
18 | dbtools.clean(function(e){
19 | dbtools.load(["../fixtures/Categories.js"],db,function(err){
20 | should.not.exist(err);
21 | done();
22 | });
23 | });
24 | });
25 |
26 |
27 | after(function(done){
28 | dbtools.clean(function(){
29 | done();
30 | });
31 | });
32 |
33 |
34 |
35 |
36 | it('POST /register should return 200 ',function(done){
37 | var r={
38 | email:"reg1@test.com",
39 | firstname:"first",
40 | lastname:"last",
41 | password:"123456",
42 | confirm:"123456"
43 | };
44 |
45 | request(app)
46 | .post('/register')
47 | .send(r)
48 | .end(function(err,res){
49 | res.should.have.status(200);
50 | done();
51 | });
52 | });
53 |
54 |
55 |
56 |
57 | it('POST /login return 200',function(done){
58 | request(app)
59 | .post('/login')
60 | .send({ email:"reg1@test.com", provider:'local', password:'123456' })
61 | .end(function(err,res){
62 | res.should.have.status(200);
63 | res.body.email.address.should.equal("reg1@test.com");
64 | should.not.exist(res.body.hash)
65 | should.not.exist(res.body.salt)
66 | cookie = res.headers['set-cookie'];
67 | user=res.body;
68 | //res.headers.location.should.equal('/');
69 | done();
70 | });
71 | });
72 |
73 |
74 |
75 | it('POST without phone /v1/users/ should return 400',function(done){
76 | var u=_.extend({},user)
77 | u.phoneNumbers=[];
78 | u.addresses=[]
79 | request(app)
80 | .post('/v1/users/'+user.id)
81 | .send(u)
82 | .set('cookie', cookie)
83 | .end(function(err,res){
84 | res.should.have.status(400);
85 | res.text.should.containEql('au moins un téléphone')
86 | //console.log(res.body.addresses[0])
87 | done()
88 | });
89 | });
90 |
91 | it('POST without phone for reminder /v1/users/ should return 200',function(done){
92 | var u=_.extend({},user)
93 | u.addresses=[]
94 | u.phoneNumbers=[];
95 | u.save_reminder=true;
96 | request(app)
97 | .post('/v1/users/'+user.id)
98 | .send(u)
99 | .set('cookie', cookie)
100 | .end(function(err,res){
101 | res.should.have.status(200);
102 | res.body.phoneNumbers.length.should.equal(0);
103 | done()
104 | });
105 | });
106 |
107 |
108 | it('POST with phone /v1/users/ should return 200',function(done){
109 | var u=_.extend({},user)
110 | u.phoneNumbers=[{number:'076.378.89.98',what:'mobile'}]
111 | u.addresses=[]
112 | request(app)
113 | .post('/v1/users/'+user.id)
114 | .send(u)
115 | .set('cookie', cookie)
116 | .end(function(err,res){
117 | res.should.have.status(200);
118 | res.body.phoneNumbers.length.should.equal(1);
119 | res.body.phoneNumbers[0].number.should.equal('076.378.89.98')
120 | done()
121 | });
122 | });
123 |
124 |
125 |
126 | });
127 |
128 |
--------------------------------------------------------------------------------
/test/api.users.update.secure.admin.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");require("should-http");
7 | var data = dbtools.fixtures(["Users.js","Categories.js","Shops.js",'Products.js']);
8 |
9 |
10 | describe("api.users", function(){
11 | var request= require('supertest');
12 |
13 | var _=require('underscore');
14 |
15 | var cookie;
16 |
17 | before(function(done){
18 | dbtools.clean(function(e){
19 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Shops.js","../fixtures/Products.js"],db,function(err){
20 | should.not.exist(err);
21 | done();
22 | });
23 | });
24 | });
25 |
26 |
27 | after(function(done){
28 | dbtools.clean(function(){
29 | done();
30 | });
31 | });
32 |
33 |
34 | var user;
35 |
36 | it('POST /login should return 200',function(done){
37 | request(app)
38 | .post('/login')
39 | .send({ email:"evaleto@gmail.com", provider:'local', password:'password' })
40 | .end(function(err,res){
41 | res.should.have.status(200);
42 | cookie = res.headers['set-cookie'];
43 | user=res.body;
44 | done();
45 | });
46 | });
47 |
48 | it('POST update user, with different user.email.status be ok for admin',function(done){
49 | var u=data.Users[1];
50 | request(app)
51 | .post('/v1/users/'+user.id)
52 | .send(_.extend({},u,{email:{status:false}}))
53 | .set('cookie', cookie)
54 | .end(function (err,res) {
55 | res.should.have.status(200);
56 | res.body.email.status.should.equal(false)
57 | res.body.email.address.should.equal(u.email.address)
58 | done();
59 | })
60 | });
61 |
62 | it('POST update other user with admin role, should return 200',function(done){
63 | var u=data.Users[0];
64 | request(app)
65 | .post('/v1/users/'+data.Users[0].id)
66 | .send(u)
67 | .set('cookie', cookie)
68 | .end(function (err,res) {
69 | res.should.have.status(200);
70 | res.body.id.should.equal(data.Users[0].id)
71 | done();
72 | })
73 | });
74 |
75 |
76 | });
77 |
78 |
--------------------------------------------------------------------------------
/test/db.maintain.js:
--------------------------------------------------------------------------------
1 | var app = require("../app");
2 |
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");
7 | var data = dbtools.fixtures(["Users.js","Categories.js","Shops.js"]);
8 |
9 | var DbMaintain = db.model('DbMaintain');
10 |
11 |
12 | describe("DbMaintain", function(){
13 | var _ = require("underscore");
14 |
15 | var error, log;
16 |
17 |
18 | before(function(done){
19 | dbtools.clean(function(){
20 | done();
21 | });
22 | });
23 |
24 | it("Find latest version with no entry", function(done){
25 | DbMaintain.findLatestVersion(function(err, version){
26 | should.not.exist(err);
27 | version.should.equal(0);
28 | done();
29 | });
30 | });
31 |
32 |
33 | it("First DbMaintain entry", function(done){
34 | var dbm={
35 | version: 1,
36 | log:"standard log",
37 | };
38 | DbMaintain.save(dbm, function(err, new_dbm){
39 | should.not.exist(err);
40 | new_dbm['version'].should.equal(dbm['version'])
41 | done();
42 | });
43 | });
44 |
45 |
46 | it("Add DbMaintain entry", function(done){
47 | var dbm={
48 | version: 2,
49 | log:"new log",
50 | };
51 | DbMaintain.save(dbm, function(err, new_dbm){
52 | should.not.exist(err);
53 | new_dbm['version'].should.equal(dbm['version'])
54 | done();
55 | });
56 | });
57 |
58 | it("Find all entries", function(done){
59 | DbMaintain.findAll(function(err, version){
60 | should.not.exist(err);
61 | version.length.should.equal(2);
62 | done();
63 | });
64 | });
65 |
66 | it("Find lates version", function(done){
67 | DbMaintain.findLatestVersion(function(err, version){
68 | should.not.exist(err);
69 | version.should.equal(2);
70 | done();
71 | });
72 | });
73 |
74 | });
75 |
--------------------------------------------------------------------------------
/test/fixtures.js:
--------------------------------------------------------------------------------
1 |
2 | var app = require("../app");
3 | var db = require("mongoose");
4 | var should = require("should");
5 |
6 |
7 | var dbtools = require("./fixtures/dbtools");
8 | var data = dbtools.fixtures(["Users.js","Categories.js"]);
9 |
10 | describe("mongoose.fixtures", function(){
11 |
12 | before(function(done){
13 | dbtools.clean(function(err){
14 | should.not.exist(err)
15 | done();
16 | });
17 | });
18 |
19 |
20 | after(function(done){
21 | dbtools.clean(function(err){
22 | should.not.exist(err)
23 | done();
24 | });
25 | });
26 |
27 |
28 | it('load json from dbtools.fixtures',function(done){
29 | should.exist(data.Users)
30 | should.exist(data.Categories)
31 | done()
32 | });
33 |
34 | it('load users',function(done){
35 | dbtools.load(["../fixtures/Users.js"],db, function(err){
36 | should.not.exist(err)
37 | db.model('Users').find({},function(e,users){
38 | users.length.should.equal(5);
39 | done();
40 | });
41 | });
42 | });
43 |
44 | it('check user password after loading fixture',function(done){
45 | var u=data.Users[0];
46 | db.model('Users').authenticate(u.email.address, u.password, function(err,user){
47 | user.email.address.should.equal(u.email.address);
48 | done();
49 | });
50 | });
51 |
52 | it('load categories',function(done){
53 | dbtools.load(["../fixtures/Categories.js"],db, function(err){
54 | should.not.exist(err)
55 | db.model('Categories').find({},function(e,docs){
56 | docs.length.should.equal(4);
57 | done();
58 | });
59 | });
60 | });
61 |
62 | it('load shops',function(done){
63 | dbtools.load(['../fixtures/Shops.js'],db, function(err,d,c){
64 | should.not.exist(err)
65 | db.model('Shops').find({},function(e,docs){
66 | docs.length.should.equal(4);
67 | done();
68 | });
69 | });
70 | });
71 |
72 | it('load products',function(done){
73 | dbtools.load(['../fixtures/Products.js'],db, function(err,d,c){
74 | should.not.exist(err)
75 | db.model('Products').find({},function(e,docs){
76 | docs.length.should.equal(3);
77 | done();
78 | });
79 | });
80 | });
81 |
82 | });
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/test/fixtures/Categories.js:
--------------------------------------------------------------------------------
1 | var ObjectId = require('mongodb').ObjectID;
2 |
3 | exports.Categories=[{
4 | _id:new ObjectId('115ec12e56a8d5961e000000'),
5 | name:"alimentaire",
6 | slug:"alimentaire",
7 | weight:1,
8 | type:"Catalog"
9 | },{
10 | _id:new ObjectId('115ec12e56a8d5961e000001'),
11 | name:"Fruits",
12 | slug:"fruits",
13 | weight:2,
14 | type:"Category"
15 | },{
16 | _id:new ObjectId('115ec12e56a8d5961e000002'),
17 | name:"Légumes",
18 | slug:"legumes",
19 | weight:1,
20 | type:"Category"
21 | },{
22 | _id:new ObjectId('115ec12e56a8d5961e000003'),
23 | name:"Poissons",
24 | slug:"poissons",
25 | weight:0,
26 | type:"Category"
27 | }
28 | ];
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/test/fixtures/Documents.js:
--------------------------------------------------------------------------------
1 | var ObjectId = require('mongodb').ObjectID;
2 |
3 | // 12345 ==> evaleto@gluck.com
4 | // 12346 ==> evaleto@gmail.com
5 | // 12347 ==> delphine@gmail.com
6 |
7 | exports.Documents=[{
8 | title: 'fixture titre',
9 | slug: 'fixture-titre',
10 | header:'##test1',
11 | content:'##test1',
12 | photo:{
13 | header:'http://photooooz',
14 | bundle:['http://photooooz']
15 | },
16 |
17 | created: new Date(),
18 | updated: new Date(),
19 | available:true,
20 | published:false,
21 |
22 | skus:[12345,12346,12347],
23 | type: 'page',
24 | owner:12345
25 | }
26 | ];
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/test/fixtures/Products.js:
--------------------------------------------------------------------------------
1 | var ObjectId = require('mongodb').ObjectID;
2 | var d=require('./Categories');
3 |
4 | // shop[0](un-autre-shop, id:0004, status:true, owner:gluck)
5 | // shop[1](mon-shop, id:0005, status:false, owner:gmail)
6 | // shop[2](invalid-shop, id:0006, status:Date.now, owner:gluck)
7 | exports.Products=[{
8 | _id : new ObjectId(),
9 | sku:12345,
10 | title: "Test product bio 1",
11 | details:{
12 | description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ",
13 | comment:"Temps de cuisson : 16 minutes",
14 | homemade:true,
15 | natural:false,
16 | bio:true,
17 | },
18 |
19 | attributes:{
20 | available:true,
21 | comment:false,
22 | discount:false
23 | },
24 |
25 | pricing: {
26 | stock:10,
27 | price:3.80,
28 | discount:3.0,
29 | part:'100gr'
30 | },
31 | photo:{
32 | url:"http://photooooz"
33 | },
34 | //un-autre-shop, status:true, owner:gluck
35 | vendor:ObjectId('515ec12e56a8d5961e000004')
36 | },{
37 | _id : new ObjectId(),
38 | sku:12346,
39 | title: "Test product 2",
40 | details:{
41 | description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ",
42 | comment:"Temps de cuisson : 16 minutes",
43 | homemade:true,
44 | natural:false,
45 | bio:false,
46 | },
47 | attributes:{
48 | available:true,
49 | comment:false,
50 | discount:false
51 | },
52 | pricing: {
53 | stock:10,
54 | price:3.80,
55 | part:'100gr'
56 | },
57 | photo:{
58 | url:"http://photooooz"
59 | },
60 | categories: d.Categories[3]._id ,
61 | //un-autre-shop, status:true, owner:gluck
62 | vendor:'515ec12e56a8d5961e000004'
63 | },{
64 | _id : new ObjectId(),
65 | sku:12347,
66 | title: "Test product bio 3",
67 | details:{
68 | description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ",
69 | comment:"Temps de cuisson : 16 minutes",
70 | homemade:true,
71 | natural:false,
72 | bio:true,
73 | },
74 | attributes:{
75 | available:true,
76 | comment:false,
77 | discount:false
78 | },
79 | pricing: {
80 | stock:10,
81 | price:3.80,
82 | discount:3.0,
83 | part:'100gr'
84 | },
85 | photo:{
86 | url:"http://photooooz"
87 | },
88 | categories: d.Categories[3]._id ,
89 | //mon-shop, id:0005, status:false, owner:gmail
90 | vendor:'515ec12e56a8d5961e000005'
91 | }
92 | ];
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/test/fixtures/Products.more.js:
--------------------------------------------------------------------------------
1 | var ObjectId = require('mongodb').ObjectID;
2 | var data=require('./Categories.js');
3 |
4 | // 2products ->shop[0](un-autre-shop, id:0004, status:true, owner:gluck)
5 | // 1product ->shop[1](mon-shop, id:0005, status:false, owner:gmail)
6 | // 0product ->shop[2](invalid-shop, id:0006, status:Date.now, owner:gluck)
7 |
8 | // data.Categories[0] -> alimentaire
9 | // data.Categories[1] -> fruits
10 | // data.Categories[2] -> legumes
11 | // data.Categories[3] -> poissons
12 |
13 | exports.Products=[{
14 | _id : new ObjectId(),
15 | sku:1000001,
16 | title: "Product 1 with cat",
17 | details:{
18 | description:"description",
19 | comment:"Temps de cuisson : 16 minutes",
20 | homemade:true,
21 | natural:false,
22 | bio:false,
23 | },
24 |
25 | attributes:{
26 | available:true,
27 | comment:false,
28 | discount:true
29 | },
30 |
31 | pricing: {
32 | stock:10,
33 | price:3.80,
34 | discount:3.0,
35 | part:'100gr'
36 | },
37 | /* weight:0,1 */
38 | categories: data.Categories[1]._id,
39 | //un-autre-shop, id:0004, status:true, owner:gluck
40 | vendor:'515ec12e56a8d5961e000004'
41 | },{
42 | _id : new ObjectId(),
43 | sku:1000002,
44 | title: "Product 2 with cat",
45 | details:{
46 | description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ",
47 | comment:"Temps de cuisson : 16 minutes",
48 | homemade:true,
49 | natural:true,
50 | bio:true,
51 | },
52 | attributes:{
53 | available:true,
54 | comment:false,
55 | discount:false,
56 | home:true
57 | },
58 | pricing: {
59 | stock:10,
60 | price:3.80,
61 | part:'0.75L'
62 | },
63 | /* weight:2 */
64 | categories:data.Categories[3]._id,
65 | //un-autre-shop, id:0004, status:true, owner:gluck
66 | vendor:'515ec12e56a8d5961e000004'
67 | },{
68 | _id : new ObjectId(),
69 | sku:1000003,
70 | title: "Product 3 with cat",
71 | details:{
72 | description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ",
73 | comment:"Temps de cuisson : 16 minutes",
74 | homemade:true,
75 | natural:false,
76 | bio:true,
77 | },
78 | attributes:{
79 | available:true,
80 | comment:false,
81 | discount:false
82 | },
83 | pricing: {
84 | stock:10,
85 | price:3.80,
86 | discount:3.0,
87 | part:'0.75L'
88 | },
89 | categories: data.Categories[1]._id,
90 | //mon-shop, id:0005, status:false, owner:gmail
91 | vendor:'515ec12e56a8d5961e000005'
92 | }
93 | ];
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/test/fixtures/Products.sort.js:
--------------------------------------------------------------------------------
1 | var ObjectId = require('mongodb').ObjectID;
2 | var data=require('./Categories.js');
3 |
4 | // 2products ->shop[0](un-autre-shop, id:0004, status:true, owner:gluck)
5 | // 1product ->shop[1](mon-shop, id:0005, status:false, owner:gmail)
6 | // 0product ->shop[2](invalid-shop, id:0006, status:Date.now, owner:gluck)
7 |
8 | exports.Products=[{
9 | _id : new ObjectId(),
10 | sku:1000001,
11 | title: "Product 1 with cat",
12 | details:{
13 | description:"description",
14 | comment:"Temps de cuisson : 16 minutes",
15 | homemade:true,
16 | natural:false,
17 | bio:false,
18 | },
19 |
20 | attributes:{
21 | available:true,
22 | comment:false,
23 | discount:false
24 | },
25 |
26 | pricing: {
27 | stock:10,
28 | price:3.80,
29 | discount:3.0,
30 | },
31 | /* weight:0,1 */
32 | categories: data.Categories[1]._id,
33 | //un-autre-shop, id:0004, status:true, owner:gluck
34 | vendor:'515ec12e56a8d5961e000004'
35 | },{
36 | _id : new ObjectId(),
37 | sku:1000002,
38 | title: "Product 2 with cat",
39 | details:{
40 | description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ",
41 | comment:"Temps de cuisson : 16 minutes",
42 | homemade:true,
43 | natural:true,
44 | bio:true,
45 | },
46 | attributes:{
47 | available:true,
48 | comment:false,
49 | discount:false
50 | },
51 | pricing: {
52 | stock:10,
53 | price:3.80,
54 | discount:3.0,
55 | part:'0.75L'
56 | },
57 | /* weight:2 */
58 | categories: data.Categories[3]._id,
59 | //un-autre-shop, id:0004, status:true, owner:gluck
60 | vendor:'515ec12e56a8d5961e000004'
61 | },{
62 | _id : new ObjectId(),
63 | sku:1000003,
64 | title: "Product 3 with cat",
65 | details:{
66 | description:"Gragnano de sa colline qui donne sur le Golfe de Naples, est depuis le XVI siècle la patrie de la pasta. ",
67 | comment:"Temps de cuisson : 16 minutes",
68 | homemade:true,
69 | natural:false,
70 | bio:true,
71 | },
72 | attributes:{
73 | available:true,
74 | comment:false,
75 | discount:false
76 | },
77 | pricing: {
78 | stock:10,
79 | price:3.80,
80 | discount:3.0,
81 | part:'0.75L'
82 | },
83 | categories: data.Categories[2]._id,
84 | //mon-shop, id:0005, status:false, owner:gmail
85 | vendor:'515ec12e56a8d5961e000004'
86 | }
87 | ];
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/test/fixtures/Wallets.js:
--------------------------------------------------------------------------------
1 |
2 | var ObjectId = require('mongoose').Schema.Types.ObjectID;
3 |
4 | // 12345 ==> evaleto@gluck.com
5 | // 12346 ==> evaleto@gmail.com
6 | // 12347 ==> delphine@gmail.com
7 |
8 | exports.Wallets=[{
9 | id:'12345',
10 | apikey:config.payment.wallet.apikey,
11 | description: 'this is a demo wallet',
12 | email: 'evaleto@gluck.com',
13 | card:{
14 | last4: '4657',
15 | number: '4091517362214657',
16 | expiry: new Date('Tue Nov 08 2016 23:59:00 GMT+0100 (CET)')
17 | },
18 | external_account: {
19 | name:'Demo Wallet',
20 | iban:'BE68539007547034'
21 | },
22 | transfers_enabled:false,
23 | transfers: [],
24 | transactions: [],
25 | created: new Date('Mon Nov 09 2015 08:20:21 GMT+0100 (CET)'),
26 | updated: new Date('Mon Nov 09 2015 08:20:21 GMT+0100 (CET)'),
27 | balance: 0,
28 | wid: 'wa_1234567890'
29 | },
30 | {
31 | id:'12346',
32 | apikey:config.payment.wallet.apikey,
33 | description: 'this is a demo wallet',
34 | email: 'evaleto@gmail.com',
35 | card:{
36 | last4: '1520',
37 | number: '4091002818331520',
38 | expiry: new Date('Tue Nov 08 2016 23:59:00 GMT+0100 (CET)')
39 | },
40 | external_account: {
41 | name:'Demo Wallet',
42 | iban:'BE68539007547034'
43 | },
44 | transfers_enabled:false,
45 | transfers: [],
46 | transactions: [],
47 | created: new Date('Mon Nov 09 2015 08:20:21 GMT+0100 (CET)'),
48 | updated: new Date('Mon Nov 09 2015 08:20:21 GMT+0100 (CET)'),
49 | balance: 0,
50 | wid: 'wa_1234567891'
51 | },
52 | {
53 | id:'12347',
54 | apikey:config.payment.wallet.apikey,
55 | description: 'this is a demo wallet',
56 | email: 'delphine@gmail.com',
57 | card:{
58 | last4: '1282',
59 | number: '2923209776891282',
60 | expiry: new Date('Tue Nov 08 2016 23:59:00 GMT+0100 (CET)')
61 | },
62 | external_account: {
63 | name:'Demo Wallet',
64 | iban:'BE68539007547034'
65 | },
66 | transfers_enabled:false,
67 | transfers: [],
68 | transactions: [],
69 | created: new Date('Mon Nov 09 2015 08:20:21 GMT+0100 (CET)'),
70 | updated: new Date('Mon Nov 09 2015 08:20:21 GMT+0100 (CET)'),
71 | balance: 0,
72 | wid: 'wa_1234567892'
73 | }];
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/test/fixtures/dbtools.js:
--------------------------------------------------------------------------------
1 |
2 | var async = require("async");
3 | var db = require("mongoose");
4 |
5 | var fx = require('pow-mongoose-fixtures');
6 |
7 |
8 | exports.clean=function(callback){
9 | if (process.env.NODE_ENV!=='test'){
10 | console.log('cannot run test without test environement: NODE_ENV=test mocha')
11 | process.exit(1);
12 | }
13 |
14 | var collections=['Users','Categories','Shops','Products','Sequences','DbMaintain', 'Emails','Wallets'];
15 | var iterator = function(name, nextcb){
16 | db.model(name).remove({},function(e){
17 | nextcb(e);
18 | });
19 | };
20 | async.forEach(collections, iterator,callback);
21 | };
22 |
23 | exports.fixtures=function(names){
24 | if (process.env.NODE_ENV!=='test'){
25 | console.log('cannot run test without test environement: NODE_ENV=test mocha')
26 | process.exit(1);
27 | }
28 |
29 | var data={};
30 | names.forEach(function(name) {
31 | var fx=require('../fixtures/'+name);
32 | Object.keys(fx).forEach(function(model){
33 | data[model]=fx[model];
34 | });
35 | });
36 | return data;
37 | }
38 | exports.load=function(fixtures, cb, callback){
39 | if (process.env.NODE_ENV!=='test'){
40 | console.log('cannot run test without test environement: NODE_ENV=test mocha')
41 | process.exit(1);
42 | }
43 |
44 | var iterator = function(fixture, nextcb){
45 | fx.load(fixture,db, nextcb);
46 | };
47 | async.forEach(fixtures, iterator,callback);
48 | }
49 |
50 |
51 |
--------------------------------------------------------------------------------
/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --require should
2 | -R spec
3 | --ui bdd
4 |
5 |
--------------------------------------------------------------------------------
/test/order.find.user.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require('mongoose');
5 | var dbtools = require("./fixtures/dbtools");
6 | var should = require("should");
7 | var data = dbtools.fixtures(["Users.js","Categories.js","Orders.find.js"]);
8 |
9 | var Products=db.model('Products')
10 | , Orders=db.model('Orders')
11 | , today=new Date()
12 | , toshortDay
13 | , okDay;
14 |
15 |
16 | /**
17 | * find order with criteria:
18 | * - closed(all or with date), open
19 | * - filter by shipping date
20 | * - filter by shop slug
21 | */
22 |
23 | describe("orders.find.user", function(){
24 | var _ = require("underscore");
25 |
26 | var nextday=Orders.findNextShippingDay();
27 | var monday=Orders.jumpToNextWeekDay(new Date(),1);
28 |
29 | // on friday next shipping day equal monday
30 | // If days equal , orders count are different
31 | var dateEqual=(monday.getDay()==nextday.getDay())
32 |
33 |
34 | before(function(done){
35 | dbtools.clean(function(e){
36 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Orders.find.js"],db,function(err){
37 | should.not.exist(err);
38 | // Orders.printInfo()
39 | // Orders.find({}).exec(function(e,os){
40 | // os.forEach(function(o){o.print()})
41 | // })
42 |
43 | done();
44 | });
45 | });
46 | });
47 |
48 |
49 | after(function(done){
50 | dbtools.clean(function(){
51 | done();
52 | });
53 | });
54 |
55 | it("find all orders (3) for user evaleto", function(done){
56 | var criteria={
57 | user: 12346,
58 | }
59 | db.model('Orders').findByCriteria(criteria, function(err,order){
60 | should.not.exist(err)
61 | order.length.should.equal(4)
62 | order[0].customer.id.should.equal(12346)
63 | done();
64 | });
65 | });
66 |
67 | it.skip("find open orders (3) for user evaleto", function(done){
68 | var criteria={
69 | user: 12346,
70 | closed:null
71 | }
72 | db.model('Orders').findByCriteria(criteria, function(err,order){
73 | should.not.exist(err)
74 | order[0].customer.id.should.equal(12346)
75 | order.length.should.equal(3)
76 | done();
77 | });
78 | });
79 |
80 | it("find closed orders (1) for user evaleto", function(done){
81 | var criteria={
82 | user: 12346,
83 | closed:true
84 | }
85 | db.model('Orders').findByCriteria(criteria, function(err,order){
86 | should.not.exist(err)
87 | order[0].customer.id.should.equal(12346)
88 | order.length.should.equal(1)
89 | done();
90 | });
91 | });
92 |
93 |
94 | });
95 |
96 |
--------------------------------------------------------------------------------
/test/products.find.disabled.js:
--------------------------------------------------------------------------------
1 | var app = require("../app");
2 |
3 | var db = require("mongoose");
4 |
5 |
6 | var dbtools = require("./fixtures/dbtools");
7 | var should = require("should");
8 | var data = dbtools.fixtures(["Users.js","Categories.js","Products.disabled.js"]);
9 | var Users=db.model('Users');
10 |
11 |
12 | describe("products.find.disabled:", function(){
13 | var async= require("async");
14 | var _ = require("underscore");
15 | var Products=db.model('Products');
16 |
17 |
18 | before(function(done){
19 | dbtools.clean(function(e){
20 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Products.disabled.js"],db,function(err){
21 | should.not.exist(err);
22 | done();
23 | });
24 | });
25 | });
26 |
27 |
28 | after(function(done){
29 | dbtools.clean(function(){
30 | done();
31 | })
32 | });
33 |
34 | //product 1 not available , but shop is available
35 | //product 2 available , shop not available
36 | //product 3 available , shop closed
37 | //product 4 available , shop will be closed in futur
38 | //product 5 available , shop was closed in past
39 | it("only product 4, 5 should be available", function(done){
40 | Products.findByCriteria({status:true,available:true},function(err,products){
41 | should.not.exist(err);
42 | should.exist(products);
43 | console.log('find',products.map(function (p) {return p.sku;}));
44 | products.length.should.equal(2)
45 | products[0].sku.should.equal(1000004);
46 | products[1].sku.should.equal(1000005);
47 | done();
48 | });
49 | });
50 |
51 |
52 | it.skip("Product could have a related products", function(done){
53 | });
54 |
55 | it.skip("Product could have variations", function(done){
56 | });
57 |
58 | it.skip("Control if out of stock products can still be shown and are available for purchase", function(done){
59 | });
60 |
61 |
62 | });
63 |
64 |
--------------------------------------------------------------------------------
/test/products.find.more.js:
--------------------------------------------------------------------------------
1 | var app = require("../app");
2 |
3 | var db = require("mongoose");
4 |
5 |
6 | var dbtools = require("./fixtures/dbtools");
7 | var should = require("should");
8 | var data = dbtools.fixtures(["Users.js","Categories.js","Products.more.js","Shops.js"]);
9 | var Users=db.model('Users');
10 |
11 |
12 | describe("products.find.more", function(){
13 | var _ = require("underscore");
14 | var Products=db.model('Products');
15 |
16 |
17 | before(function(done){
18 | dbtools.clean(function(e){
19 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Shops.js","../fixtures/Products.more.js"],db,function(err){
20 | should.not.exist(err);
21 | done();
22 | });
23 | });
24 | });
25 |
26 |
27 | after(function(done){
28 | dbtools.clean(function(){
29 | done();
30 | })
31 | });
32 |
33 | it("Find popular products ", function(done){
34 | var criteria={ popular: true };
35 | Products.findByCriteria(criteria,function(err,products){
36 | should.not.exist(err);
37 | should.exist(products);
38 | products.length.should.equal(3)
39 | done();
40 | });
41 | });
42 |
43 |
44 |
45 | it("Find home products ", function(done){
46 | var criteria={ home:true };
47 | Products.findByCriteria(criteria,function(err,products){
48 | should.not.exist(err);
49 | should.exist(products);
50 | products.length.should.equal(1)
51 | done();
52 | });
53 |
54 | });
55 |
56 | it("Find discount products ", function(done){
57 | var criteria={ discount:true };
58 | Products.findByCriteria(criteria,function(err,products){
59 | should.not.exist(err);
60 | should.exist(products);
61 | products.length.should.equal(1)
62 | done();
63 | });
64 | });
65 |
66 | it("Find discount products SKU ", function(done){
67 | Products.findDiscountSKUs(function(err,skus){
68 | should.not.exist(err);
69 | should.exist(skus);
70 | skus.length.should.equal(1);
71 | (typeof skus[0]).should.equal('number');
72 | done();
73 | });
74 |
75 | });
76 |
77 |
78 |
79 |
80 | });
81 |
82 |
--------------------------------------------------------------------------------
/test/products.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | // Use a different DB for tests
3 | var app = require("../app");
4 |
5 | var db = require('mongoose');
6 | var dbtools = require("./fixtures/dbtools");
7 | var should = require("should");
8 | var data = dbtools.fixtures(["Users.js","Categories.js","Shops.js"]);
9 |
10 |
11 |
12 | describe("products", function(){
13 | var _ = require("underscore");
14 |
15 | before(function(done){
16 | dbtools.clean(function(e){
17 | dbtools.load(["../fixtures/Users.js","../fixtures/Categories.js","../fixtures/Shops.js"],db,function(err){
18 | should.not.exist(err);
19 | done();
20 | });
21 | });
22 | });
23 |
24 |
25 | after(function(done){
26 | dbtools.clean(function(){
27 | done();
28 | });
29 | });
30 |
31 |
32 | it.skip("Find products by Manufacturer and Category and details ", function(done){
33 | });
34 |
35 | it.skip("Product can be enabled or disabled", function(done){
36 | });
37 |
38 | it.skip("Product could have a related products", function(done){
39 | });
40 |
41 | it.skip("Product could have variations", function(done){
42 | });
43 |
44 | it.skip("Control if out of stock products can still be shown and are available for purchase", function(done){
45 | });
46 |
47 |
48 |
49 | });
50 |
51 |
--------------------------------------------------------------------------------
/test/sequences.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app"),
3 | db = require('mongoose'),
4 | dbtools = require("./fixtures/dbtools"),
5 | should = require("should");
6 |
7 |
8 | describe("sequences", function(){
9 |
10 | var SKU=db.model('Sequences').initNumber('sku');
11 | before(function(done){
12 | dbtools.clean(function(){
13 | done();
14 | });
15 | });
16 |
17 |
18 | after(function(done){
19 | dbtools.clean(function(){
20 | done();
21 | });
22 | });
23 |
24 | it("First SKU ", function(done){
25 | db.model('Sequences').nextSku(function(err,sku){
26 | sku.should.equal(SKU);
27 | done();
28 | });
29 | });
30 |
31 | it("Next SKU, ", function(done){
32 | db.model('Sequences').nextSku(function(err,sku){
33 | sku.should.equal(SKU+1);
34 | done();
35 | });
36 | });
37 |
38 | it("Next SKU, ", function(done){
39 | db.model('Sequences').next('sku',function(err,sku){
40 | sku.should.equal(SKU+2);
41 | done();
42 | });
43 | });
44 |
45 | it("Next SKU with promise ", function(done){
46 | db.model('Sequences').nextSku().then(function(sku){
47 | sku.should.equal(SKU+3);
48 | done();
49 | });
50 | });
51 |
52 |
53 | it("Race condition without init",function (done) {
54 | require("async").parallelLimit([
55 | function(cb){
56 | db.model('Sequences').next('sku',cb);
57 | },
58 | function(cb){
59 | db.model('Sequences').next('sku',cb);
60 | },
61 | function(cb){
62 | db.model('Sequences').next('sku',cb);
63 | },
64 | function(cb){
65 | db.model('Sequences').nextSku(cb);
66 | }
67 | ],4, function(err,seq){
68 | seq.length.should.equal(4)
69 | seq.should.containEql(1000004)
70 | seq.should.containEql(1000005)
71 | seq.should.containEql(1000006)
72 | seq.should.containEql(1000007)
73 | done()
74 | });
75 |
76 |
77 | })
78 |
79 | it.skip("Race condition with promise",function (done) {
80 | require("async").parallelLimit([
81 | function(cb){
82 | db.model('Sequences').next('other',cb);
83 | },
84 | function(cb){
85 | db.model('Sequences').next('other',cb);
86 | },
87 | function(cb){
88 | db.model('Sequences').next('other',cb);
89 | },
90 | function(cb){
91 | db.model('Sequences').next('other',cb);
92 | }
93 | ],4, function(err,seq){
94 | done()
95 | });
96 |
97 |
98 | })
99 |
100 |
101 |
102 | });
103 |
104 |
--------------------------------------------------------------------------------
/test/users.reminder.js:
--------------------------------------------------------------------------------
1 | // Use a different DB for tests
2 | var app = require("../app");
3 |
4 | var db = require("mongoose");
5 |
6 | var dbtools = require("./fixtures/dbtools");
7 | var should = require("should");
8 | var data = dbtools.fixtures(["Users.reminder.js"]);
9 |
10 |
11 |
12 |
13 | describe("users.reminder", function(){
14 |
15 | before(function(done){
16 | dbtools.clean(function(e){
17 | dbtools.load(["../fixtures/Users.reminder.js"],db,function(err){
18 | should.not.exist(err);
19 | // db.model('Users').find({}).exec(function(e,us) {
20 | // us.forEach(function (u) {
21 | // console.log('-------------',u.id,u.email.address,JSON.stringify(u.reminder))
22 | // })
23 | // })
24 | done();
25 | });
26 | });
27 | });
28 |
29 | after(function(done){
30 | dbtools.clean(function(){
31 | done();
32 | });
33 | });
34 |
35 |
36 | it('find users with reminder weekday(0),time(11) should return 0',function(done) {
37 | var reminder={
38 | weekdays:[0],time:11
39 | };
40 | db.model('Users').findByReminder(reminder).then(function(users) {
41 | setTimeout(function() {
42 | users.length.should.equal(0);
43 | done()
44 | });
45 | })
46 | })
47 |
48 | it('find users with reminder weekday(1),time(10) should return 0',function(done) {
49 | var reminder={
50 | weekdays:[1],time:10
51 | };
52 | db.model('Users').findByReminder(reminder).then(function(users) {
53 | setTimeout(function() {
54 | users.length.should.equal(0);
55 | done()
56 | });
57 | })
58 | })
59 |
60 | it('find users with reminder weekday(1),time(11) should return 2',function(done) {
61 | var reminder={
62 | weekdays:[1],time:11
63 | };
64 | db.model('Users').findByReminder(reminder).then(function(users) {
65 | setTimeout(function() {
66 | users.length.should.equal(2);
67 | done()
68 | });
69 | })
70 | })
71 |
72 |
73 | it('activate reminder for user evaleto@gmail.com',function(done) {
74 | db.model('Users').findAndUpdate(12346,{reminder:{active:true}}).then(function(user) {
75 | user.reminder.active.should.equal(true);
76 | should.exist(user.reminder.weekdays)
77 | should.exist(user.reminder.time)
78 | done()
79 | })
80 | })
81 |
82 | it('find activated previous reminder weekday(0),time(11) should return 1',function(done) {
83 | var reminder={
84 | weekdays:[0],time:11
85 | };
86 | db.model('Users').findByReminder(reminder).then(function(users) {
87 | setTimeout(function() {
88 | users.length.should.equal(1);
89 | done()
90 | });
91 | })
92 | })
93 |
94 | it('find users with reminder weekday 10',function(done) {
95 | done()
96 | })
97 |
98 |
99 |
100 | });
101 |
102 |
--------------------------------------------------------------------------------
/update-gh-pages.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | if git status --porcelain 2>/dev/null | grep -q .; then
3 | echo "Working copy is dirty" >&2
4 | exit 1
5 | fi
6 | rm -rf build
7 | git checkout gh-pages
8 | git merge master
9 | grunt dist
10 | git add build
11 | git commit -m 'automatic gh-pages build'
12 | git checkout master
13 |
--------------------------------------------------------------------------------
/views/500.jade:
--------------------------------------------------------------------------------
1 |
2 | block main
3 | h1 Oops something went wrong
4 | br
5 | span 500
6 |
7 | block content
8 | pre= error
9 |
--------------------------------------------------------------------------------
/views/cookie.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | title Karibou API
5 | link(href="/css/bootstrap-white.min.css", rel="stylesheet")
6 | link(href="/css/bootstrap-responsive.min.css", rel="stylesheet")
7 | script(src="js/jquery-1.9.0.min.js")
8 | script(src="js/bootstrap.min.js")
9 |
10 | body
11 |
12 | body(data-spy="scroll", data-target=".bs-docs-sidebar")
13 | block content
14 | div.alert.alert-info.fade.in
15 | button(type="button", class="close", data-dismiss="alert")
16 | p Certains navigateur demande une confirmation du cookie,
17 | a(href='http://karibou.evaletolab.ch', title="Accept Cookie") en acceptant de cliquer ce lien vous pourrez profiter pleinement de votre site
--------------------------------------------------------------------------------
/views/document.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(itemscope itemtype="http://schema.org/Article")
3 | head
4 | // http://schema.org/Article
5 | title: =getLocal(doc.title)+' ('+doc.type+')'
6 | meta(http-equiv='Content-Type', content='text/html; charset=UTF-8')
7 | meta(name='robots', content='index,follow')
8 | meta(name="viewport" content="width=device-width, initial-scale=1.0")
9 | meta(name='revised', content='#{doc.updated}')
10 |
11 |
12 | // Place this data between the tags of your website
13 | meta( name="description", content="#{getLocal(doc.header)}")
14 |
15 | // Schema.org markup for Google+
16 | meta( itemprop="name", content="#{getLocal(doc.title)}")
17 | meta( itemprop="description", content="#{getLocal(doc.header)}")
18 | meta( itemprop="image", content="#{prependUrlImage(doc.photo.header)}")
19 |
20 | // Twitter Card data
21 | meta( name="twitter:card", content="article")
22 | meta( name="twitter:title", content="#{getLocal(doc.title)}")
23 | meta( name="twitter:description", content="#{getLocal(doc.header)}")
24 | meta( name="twitter:creator", content="#{doc.signature}")
25 | meta( name="twitter:image", content="#{prependUrlImage(doc.photo.header)}")
26 |
27 | // Open Graph data
28 | meta( property="og:title", content="#{getLocal(doc.title)}" )
29 | meta( property="og:type", content="article" )
30 | meta( property="og:url", content="https://karibou.ch/content/#{doc.slug[0]}" )
31 | meta( property="og:image", content="#{prependUrlImage(doc.photo.header)}-/resize/600x/" )
32 | meta( property="og:description", content="#{getLocal(doc.header)}" )
33 | meta( property="og:site_name", content="https://karibou.ch" )
34 |
35 | // Full example with review and price
36 | // https://schema.org/price
37 | link(rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css")
38 | link(href="/css/style.css", rel="stylesheet")
39 | body
40 | div(class="container")
41 |
42 | div(class="header clearfix")
43 | nav(class="navbar navbar-default")
44 | ul(class="nav navbar-nav ")
45 | - each menu in config.shared.menu
46 | li(role="presentation" class="")
47 | if menu.active && (['karibou','howto','links'].indexOf(menu.group)!==-1)
48 | a( href="#{menu.url}"): | !{getLocal(menu.name)}
49 | li(role="presentation" class=""): a( href="/shops") Les boutiques
50 |
51 |
52 | div(class="jumbotron")
53 | h2 Des produits frais, bio, votre maraîcher, boulanger, fromager, boucher... livrés à votre porte!
54 |
55 |
56 |
57 |
58 | h1(itemprop="name"): =getLocal(doc.title)
59 | div(itemprop="description")
60 | !{md.render(getLocal(doc.header))}
61 | if doc.photo.header
62 | img(src='#{prependUrlImage(doc.photo.header)}-/resize/600x/', class="img-responsive")
63 |
64 | h1: La sélection
65 | - each product in products
66 | img(src='#{prependUrlImage(product.photo.url)}-/resize/600x/')
67 |
68 |
69 | div
70 | !{md.render(getLocal(doc.content))}
71 |
72 |
73 | h4
74 | !{(doc.updated).toDateString()} , by #{doc.signature}
75 |
--------------------------------------------------------------------------------
/views/home.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 | block content
3 | - if (!user)
4 | li: a(href='/login', rel="tooltip", title="Login") Login
5 | li: a(href='/register', rel="tooltip", title="Login") Register
6 | li: a(href='/auth/twitter', rel="tooltip", title="Login") Login with Twitter
7 | - else
8 | li: a: =user.id+'@'+user.provider
9 |
10 |
11 | li: a(href='/logout') Logout
12 |
13 |
--------------------------------------------------------------------------------
/views/homeseo.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | meta(http-equiv='Content-Type', content='text/html; charset=UTF-8')
5 | meta(name="viewport" content="width=device-width, initial-scale=1.0")
6 | meta(name='robots', content='index,follow')
7 | title: |Karibou - producteurs, artisans et épiciers online!
8 | meta(name="title", content="Karibou - producteurs, artisans et épiciers online!")
9 | meta(charset="utf-8")
10 | meta(name="description", content="Karibou - Votre maraîcher, boulanger, fromager, boucher... livrés à votre porte!")
11 | meta(name="author", content="karibou team")
12 | link(rel="canonical", href="https://karibou.ch/")
13 | link(rel="icon", type="image/png", href="/img/k-small.png" )
14 | meta(property="og:type", content="website")
15 | meta(property="og:image", content="/img/k-small.png")
16 | meta(property="og:title", content="Karibou")
17 | meta(property="og:description", content="Karibou - Votre maraîcher, boulanger, fromager, boucher... livrés à votre porte!" )
18 | meta(property="og:site_name", content="Karibou")
19 | meta(property="og:url", content="https://Karibou.ch")
20 | meta(name="twitter:site", content="@kariboulab")
21 | link(rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css")
22 | link(href="/css/style.css", rel="stylesheet")
23 | // GG analytics
24 | script(type='text/javascript').
25 | if(location.origin.indexOf('evaletolab')==-1){
26 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
27 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
28 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
29 | })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
30 | ga('require', 'displayfeatures');
31 | ga('create', 'UA-57032730-1', 'auto');
32 | }
33 | body
34 | div(class="container")
35 | div(class="header clearfix")
36 | nav(class="navbar navbar-default")
37 | ul(class="nav navbar-nav ")
38 | - each menu in config.shared.menu
39 | li(role="presentation" class="")
40 | if menu.active && (['karibou','howto','links'].indexOf(menu.group)!==-1)
41 | a( href="#{menu.url}"): | !{getLocal(menu.name)}
42 | li(role="presentation" class=""): a( href="/shops") Les boutiques
43 |
44 |
45 |
46 | div(class="jumbotron")
47 | h2 Des produits frais, bio, votre maraîcher, boulanger, fromager, boucher... livrés à votre porte!
48 | img(src="/img/hello-home.jpg", class="img-responsive img")
49 |
50 |
51 |
52 | div(class="list-group")
53 | - each cat in categories
54 | a(href="/products/category/#{cat.slug}" class="list-group-item link"): =cat.name
55 |
56 | block content
57 |
58 |
59 |
--------------------------------------------------------------------------------
/views/index.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | title karibou api - make things
5 | link(rel='stylesheet', href='/css/style.css')
6 | link(rel='stylesheet', href='http://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700&subset=latin,latin-ext')
7 | meta(http-equiv='Content-Type', content='text/html; charset=UTF-8')
8 | script(src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js')
9 | body
10 |
11 |
12 | #container
13 | h1
14 | |API documentations
15 |
--------------------------------------------------------------------------------
/views/layout.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | title Karibou API
5 | meta(name='robots', content='noindex,nofollow')
6 | link(href="/css/bootstrap-white.min.css", rel="stylesheet")
7 | link(href="/css/bootstrap-responsive.min.css", rel="stylesheet")
8 | link(href="/css/bootswatch.css", rel="stylesheet")
9 | script(src="js/jquery-1.9.0.min.js")
10 | script(src="js/bootstrap.min.js")
11 |
12 | //
13 | script(src='http://static.ak.fbcdn.net/connect/en_US/core.js')
14 | script.
15 | $(function(){
16 | var a = $('a.menu[href="' + window.location.pathname + '"]');
17 | a.parent().addClass('active');
18 | });
19 | body
20 |
21 | body(data-spy="scroll", data-target=".bs-docs-sidebar")
22 |
23 | // Navbar
24 | // ==================================================
25 | div.navbar.navbar-inverse.navbar-fixed-top
26 | div.navbar-inner
27 | div.container
28 | button( type="button", class="btn btn-navbar", data-toggle="collapse", data-target=".nav-collapse")
29 | span.icon-bar o
30 | span.icon-bar
31 | span.icon-bar
32 | a(class="brand", href="https://github.com/evaletolab/karibou-api") Karibou
33 | div.nav-collapse.collapse
34 | ul.nav
35 | li: a.menu(href="/") Home
36 | li: a.menu(href="/v1") API V1
37 | li: a.menu(href="/about") About
38 |
39 | ul(class="nav pull-right", id="main-menu-right")
40 | block content
41 |
42 | #main.container
43 | h2 Karibou API, the open source Marketplace
44 | p
45 | |Karibou is an open-source projects aim to help the creation of a online community marketplace.
46 | |The Karibou-api is the backend - for developpers - and is implemented as JSON and follow the rules of REST.
47 | - if (user)
48 | pre: =JSON.stringify(user)
49 | table.table(style="font-family: sans-serif;")
50 | thead: tr
51 | th: path
52 | th: method
53 | th: secure
54 | th: params
55 | tbody
56 | tr(colspan=4)
57 | td: b Selections
58 | each route in filter(api.get)
59 | tr(style="background-color:#eee")
60 | td: =route.path
61 | td: =route.method
62 | td: -
63 | td: =route.params
64 | tr(colspan=4)
65 | td: b Creations
66 | each route in filter(api.post)
67 | tr
68 | td: =route.path
69 | td: =route.method
70 | - if(route.callbacks.length)
71 | td: b secure
72 | - else
73 | td: -
74 | td: =route.params
75 | tr(colspan=4)
76 | td: b Deletions
77 | each route in filter(api.delete)
78 | tr(style="background-color:#eee")
79 | td: =route.path
80 | td: =route.method
81 | - if(route.callbacks[0])
82 | td: b secure
83 | - else
84 | td: -
85 | td: =route.params
86 | tr(colspan=4)
87 | td: b Updates
88 | each route in filter(api.put)
89 | tr
90 | td: =route.path
91 | td: =route.method
92 | - if(route.callbacks[0])
93 | td: b secure
94 | - else
95 | td: -
96 | td: =route.params
97 |
98 |
--------------------------------------------------------------------------------
/views/login.jade:
--------------------------------------------------------------------------------
1 | title Login to karibou
2 |
3 | div
4 | div#header
5 | h2 karibou
6 | p Log In
7 |
8 | div
9 | form(action='/login', method='POST')
10 | #login.center
11 | label(for='email') Email:
12 | input(type='text', name='email', placeholder='email@email.com')
13 | #password.center
14 | label(for='password') Password:
15 | input(type='password', name='password', placeholder='password')
16 | input(type='hidden', name='provider', value='local')
17 | #submit.button
18 | input(type='submit', value='Log Me In!') Login
19 |
--------------------------------------------------------------------------------
/views/products.jade:
--------------------------------------------------------------------------------
1 | extends homeseo
2 |
3 | block content
4 | h1: | Liste des produits
5 | div(class="list-group")
6 | - each product in products
7 | a(href="/products/#{product.sku}/#{product.slug}", class="list-group-item link", title="#{product.title}"): =product.title
8 |
9 |
10 |
--------------------------------------------------------------------------------
/views/pspstd.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | //
3 | This is example of Dynamic Template Page you can start from to personnalize the look
4 | of your payment pages.
5 | This page must be hosted on your own website. We retrieve it every time an authorization
6 | is requested. The URL of the Template Page hosted on your site is given by you in
7 | the hidden fields of the ordering form for each authorization request.
8 | You can change anything in this page but you must keep the "PAYMENT ZONE" and
9 | the $$$ strings exactly as they are.
10 | The styles and classes defined hereafter allow you to modify the lay out of
11 | the elements added by us during the authorization process. Just change the
12 | properties of those styles to fit to the look of your site.
13 | head
14 | meta(http-equiv='Content-Type', content='text/html;CHARSET=utf-8')
15 | title Demo "standard mode" Sample Template Page
16 | |
17 | style(type='text/css').
18 | body {margin:0px;}
19 | td.ncolh1 {}
20 | td.ncoltxtl {}
21 | td.ncoltxtl2 {}
22 | td.ncoltxtr {}
23 | td.ncoltxtc {}
24 | td.ncollogol {}
25 | td.ncollogor {}
26 | td.ncollogoc {}
27 | td.ncoltxtmessage {background-color : lightblue; color : lightblue; text-align : left; font-weight : bold}
28 | td.ncolinput {}
29 | td.ncolline1 {}
30 | td.ncolline2 {}
31 | input.ncol {}
32 | table.ncoltable1 { width:100%;background-color:#FCF8E3;display:none; }
33 | table.ncoltable2 { width:100%;background-color:#FCF8E3; }
34 | table.ncoltable3 { width:100%;background-color:#FCF8E3; }
35 | // for Direct Debit payments
36 | .DDtxt {text-align: left;margin-left:2em;font-weight: normal;margin-top:0;}
37 | .DDlabel {text-align: left; margin-left:4em;font-weight: normal;margin-top:0;}
38 | .DDdata {font-weight: normal;margin-top:0;}
39 | .MKtxt {text-align: left;font-weight: bold; margin-left:2em;margin-top:0;}
40 | .MKlabel {text-align: left; margin-left:4em;font-weight: normal;font-style:italic;margin-top:0;}
41 | td.ncoltxtr p.MKlabel {margin-left:0;}
42 | .MKdata {font-weight: normal;margin-top:0;}
43 | .DDimp {font-weight: bold;margin-left:2em;text-align: left;margin-top:0;}
44 | .DDsection {font-weight: bold;margin-left:0em;text-align: left; margin-top:1em; margin-bottom: 0em;}
45 | body
46 | table(border='0', width='100%')
47 | tr
48 | td(width='100%')
49 | // here is the payment form
50 | | $$$PAYMENT ZONE$$$
51 |
--------------------------------------------------------------------------------
/views/pspsuccess.jade:
--------------------------------------------------------------------------------
1 | div
2 | div#header
3 | h2 Votre mode de paiement à été correctement enregistré
4 |
--------------------------------------------------------------------------------
/views/register.jade:
--------------------------------------------------------------------------------
1 | title Register a New User
2 |
3 | div
4 | div#header
5 | h2 CrowdNotes
6 | p Register as a User
7 |
8 | div
9 | form(action='/register', method='POST')
10 | #login.center
11 | label(for='email') Email:
12 | input(type='text', name='email', placeholder='email@email.com')
13 | #password.center
14 | label(for='password') Password:
15 | input(type='password', name='password', placeholder='password')
16 | #password.center
17 | label(for='confirm') Confirm:
18 | input(type='password', name='confirm', placeholder='confirm')
19 | #first-name.center
20 | label(for='name.first') First Name:
21 | input(type='text', name='name.first', placeholder='First Name')
22 | #last-name.center
23 | label(for='name.last') Last Name:
24 | input(type='text', name='name.last', placeholder='Last Name')
25 | #submit.button
26 | input(type='submit') Register
27 |
28 | div.button
29 | a(href='/account') HOME
30 |
--------------------------------------------------------------------------------
/views/shop.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(itemscope, itemtype="http://schema.org/LocalBusiness")
3 | head
4 | // http://schema.org/LocalBusiness
5 | title: =shop.name
6 | meta(http-equiv='Content-Type', content='text/html; charset=UTF-8')
7 | meta(name="viewport" content="width=device-width, initial-scale=1.0")
8 | meta(name='robots', content='index,follow')
9 |
10 | // Place this data between the tags of your website
11 | meta( name="description", content="#{shop.description}")
12 |
13 | // Schema.org markup for Google+
14 | meta( itemprop="name", content="#{shop.name}")
15 | meta( itemprop="description", content="#{shop.description}")
16 | meta( itemprop="image", content="#{prependUrlImage(shop.photo.fg)}")
17 | meta( itemprop="url", content="https://karibou.ch/shop/#{shop.urlpath}" )
18 |
19 | // Twitter Card data
20 | meta( name="twitter:card", content="article")
21 | //meta( name="twitter:site", content="@publisher_handle")
22 | meta( name="twitter:title", content="#{shop.name}")
23 | meta( name="twitter:description", content="#{shop.description}")
24 | //meta( name="twitter:creator", content="@author_handle")
25 | meta( name="twitter:image", content="#{prependUrlImage(shop.photo.fg)}")
26 |
27 | // Open Graph data
28 | meta( property="og:title", content="#{shop.name}" )
29 | meta( property="og:url", content="https://karibou.ch/shop/#{shop.urlpath}" )
30 | meta( property="og:image", content="#{prependUrlImage(shop.photo.fg)}" )
31 | meta( property="og:description", content="#{shop.description}" )
32 | meta( property="og:site_name", content="https://karibou.ch" )
33 | link(rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css")
34 | link(href="/css/style.css", rel="stylesheet")
35 |
36 | body
37 | div(class="container")
38 | div(class="header clearfix")
39 | nav(class="navbar navbar-default")
40 | ul(class="nav navbar-nav ")
41 | - each menu in config.shared.menu
42 | li(role="presentation" class="")
43 | if menu.active && (['karibou','howto','links'].indexOf(menu.group)!==-1)
44 | a( href="#{menu.url}"): | !{getLocal(menu.name)}
45 | li(role="presentation" class=""): a( href="/shops") Les boutiques
46 |
47 | h3( class="text-muted"): |Karibou Marketplace
48 |
49 |
50 | div(class="jumbotron")
51 | h2 Des produits frais, bio, votre maraîcher, boulanger, fromager, boucher... livrés à votre porte!
52 |
53 | h1: =shop.name
54 | div: =shop.description
55 | div
56 | img(src='#{prependUrlImage(shop.photo.fg)}', class="img-responsive")
57 | h1 Boutique
58 | div(itemprop='owns')
59 | div(itemprop="name"): =shop.address.name
60 | div(itemprop="url")#{shop.name}
61 |
62 | h2 En vente sur le marché
63 | ul(class="list-group")
64 | - each place in shop.marketplace
65 | li(class="list-group-item"): =place
66 |
67 |
68 | h2 Contact
69 | ul(class="list-group", itemscope, itemtype="http://schema.org/Organization")
70 | li(class="list-group-item",itemprop="telephone"): =shop.address.phone
71 | ul(class="list-group",itemscope, itemtype="http://schema.org/PostalAddress")
72 | li(class="list-group-item", itemprop="name"): =shop.address.name
73 | li(class="list-group-item", itemprop="streetAddress"): =shop.address.streetAdress
74 | li(class="list-group-item", itemprop="addressRegion"): =shop.address.region
75 | li(class="list-group-item", itemprop="postalCode"): =shop.address.postalCode
76 |
--------------------------------------------------------------------------------
/views/shops.jade:
--------------------------------------------------------------------------------
1 | extends homeseo
2 |
3 | block content
4 | h1: | Liste des boutiques
5 | ol
6 | - each shop in shops
7 | li
8 | a( href="/shop/#{shop.urlpath}", title="#{shop.name}"): =shop.name
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/views/welcome.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | title Karibou API
5 | link(href="/css/bootstrap-white.min.css", rel="stylesheet")
6 | link(href="/css/bootstrap-responsive.min.css", rel="stylesheet")
7 | link(href="/css/bootswatch.css", rel="stylesheet")
8 | script(src="js/jquery-1.9.0.min.js")
9 | script(src="js/bootstrap.min.js")
10 |
11 |
12 | body(data-spy="scroll", data-target=".bs-docs-sidebar")
13 |
14 |
--------------------------------------------------------------------------------