Merged PetitTeton webapp with the inventory tracking app; Moved the database configuration out of git and added an example configuration; Added migrations to the mix so that we can easily update the production database and roll back changes to the database (from the command line install migrations [may not be necessary?]:
npm install -g sequelize-cli To update the database after updating the app from git (on the command line in the webapp base directory): sequelize db:migrate To undo the last migrations: sequelize db:migrate:undo
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,3 +4,5 @@ config.js
|
||||
public/main.css
|
||||
public/emailFailures.txt
|
||||
sessions/
|
||||
config/db.js
|
||||
.idea/workspace.xml
|
||||
|
||||
7
.sequelizerc
Normal file
7
.sequelizerc
Normal file
@@ -0,0 +1,7 @@
|
||||
var path=require('path');
|
||||
|
||||
//'migrations-path': 'migrations'
|
||||
|
||||
module.exports = {
|
||||
'config': path.resolve('config', 'db.js')
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
|
||||
'url' : 'postgres://PetitTeton:1qaz2wsx@localhost:5432/Petit_Teton_Apps'
|
||||
|
||||
};
|
||||
14
config/db_example.js
Normal file
14
config/db_example.js
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
|
||||
'url' : 'postgres://PetitTeton:1qaz2wsx@localhost:5432/PetitTeton'
|
||||
/*
|
||||
"development": {
|
||||
"url": "xxxxxxxxxxxxxxxx",
|
||||
"dialect": "mysql"
|
||||
},
|
||||
"production": {
|
||||
"url": "xxxxxxxxxxxxxxxx",
|
||||
"dialect": "postgres"
|
||||
}
|
||||
*/
|
||||
};
|
||||
27
migrations/20160602030143-User.js
Normal file
27
migrations/20160602030143-User.js
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (query, Sequelize) {
|
||||
var DataTypes = Sequelize; //Allow for more cut and paste :)
|
||||
|
||||
return query.createTable('User', {
|
||||
login: {
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
admin: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
},
|
||||
|
||||
down: function (query, Sequelize) {
|
||||
return query.dropTable('User');
|
||||
}
|
||||
};
|
||||
13
migrations/20160602030144-UserIndex.js
Normal file
13
migrations/20160602030144-UserIndex.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (query, Sequelize) {
|
||||
var DataTypes = Sequelize; //Allow for more cut and paste :)
|
||||
|
||||
return query.addIndex('User', ['login'], {indicesType: 'UNIQUE', indexName: 'LOGIN_INDEX'});
|
||||
},
|
||||
|
||||
down: function (query, Sequelize) {
|
||||
|
||||
}
|
||||
};
|
||||
39
migrations/20160602030145-Measure.js
Normal file
39
migrations/20160602030145-Measure.js
Normal file
@@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (query, Sequelize) {
|
||||
var DataTypes = Sequelize; //Allow for more cut and paste :)
|
||||
|
||||
return query.createTable('Measure', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
image: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true
|
||||
},
|
||||
postfix: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
},
|
||||
|
||||
down: function (query, Sequelize) {
|
||||
return query.dropTable('Measure');
|
||||
}
|
||||
};
|
||||
31
migrations/20160602030146-Venue.js
Normal file
31
migrations/20160602030146-Venue.js
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (query, Sequelize) {
|
||||
var DataTypes = Sequelize; //Allow for more cut and paste :)
|
||||
|
||||
return query.createTable('Venue', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
},
|
||||
|
||||
down: function (query, Sequelize) {
|
||||
return query.dropTable('Venue');
|
||||
}
|
||||
};
|
||||
31
migrations/20160602030147-Category.js
Normal file
31
migrations/20160602030147-Category.js
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (query, Sequelize) {
|
||||
var DataTypes = Sequelize; //Allow for more cut and paste :)
|
||||
|
||||
return query.createTable('Category', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
},
|
||||
|
||||
down: function (query, Sequelize) {
|
||||
return query.dropTable('Category');
|
||||
}
|
||||
};
|
||||
42
migrations/20160602030148-Subcategory.js
Normal file
42
migrations/20160602030148-Subcategory.js
Normal file
@@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (query, Sequelize) {
|
||||
var DataTypes = Sequelize; //Allow for more cut and paste :)
|
||||
|
||||
return query.createTable('Subcategory', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
field: 'id',
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
field: 'name',
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
},
|
||||
categoryId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Category',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'cascade',
|
||||
onDelete: 'cascade'
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
},
|
||||
|
||||
down: function (query, Sequelize) {
|
||||
return query.dropTable('Subcategory');
|
||||
}
|
||||
};
|
||||
44
migrations/20160602030149-Item.js
Normal file
44
migrations/20160602030149-Item.js
Normal file
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (query, Sequelize) {
|
||||
var DataTypes = Sequelize; //Allow for more cut and paste :)
|
||||
|
||||
return query.createTable('Item', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
counts: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
},
|
||||
subcategoryId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Subcategory',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'cascade',
|
||||
onDelete: 'cascade'
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
},
|
||||
|
||||
down: function (query, Sequelize) {
|
||||
return query.dropTable('Item');
|
||||
}
|
||||
};
|
||||
48
migrations/20160602030150-Sale.js
Normal file
48
migrations/20160602030150-Sale.js
Normal file
@@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (query, Sequelize) {
|
||||
var DataTypes = Sequelize; //Allow for more cut and paste :)
|
||||
|
||||
return query.createTable('Sale', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
date: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
},
|
||||
measure: {
|
||||
type: DataTypes.JSONB,
|
||||
allowNull: false
|
||||
},
|
||||
itemId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Item',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'cascade',
|
||||
onDelete: 'cascade'
|
||||
},
|
||||
venueId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Venue',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'cascade',
|
||||
onDelete: 'cascade'
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
},
|
||||
|
||||
down: function (query, Sequelize) {
|
||||
return query.dropTable('Sale');
|
||||
}
|
||||
};
|
||||
203
migrations/20160602035027-base.js
Normal file
203
migrations/20160602035027-base.js
Normal file
@@ -0,0 +1,203 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (query, Sequelize) {
|
||||
var DataTypes = Sequelize; //Allow for more cut and paste :)
|
||||
|
||||
return query.createTable('User', {
|
||||
login: {
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
admin: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
query.addIndex('User', ['login'], {indicesType: 'UNIQUE', indexName: 'LOGIN_INDEX'});
|
||||
|
||||
query.createTable('Measure', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
image: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true
|
||||
},
|
||||
postfix: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
|
||||
query.createTable('Venue', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
|
||||
query.createTable('Category', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
|
||||
query.createTable('Subcategory', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
field: 'id',
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
field: 'name',
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
},
|
||||
categoryId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Category',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'cascade',
|
||||
onDelete: 'cascade'
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
|
||||
query.createTable('Item', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
counts: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: false
|
||||
},
|
||||
visible: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
},
|
||||
subcategoryId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Subcategory',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'cascade',
|
||||
onDelete: 'cascade'
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
|
||||
query.createTable('Sale', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
allowNull: false,
|
||||
autoIncrement: true
|
||||
},
|
||||
date: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false
|
||||
},
|
||||
measure: {
|
||||
type: DataTypes.JSONB,
|
||||
allowNull: false
|
||||
},
|
||||
itemId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Item',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'cascade',
|
||||
onDelete: 'cascade'
|
||||
},
|
||||
venueId: {
|
||||
type: Sequelize.INTEGER,
|
||||
references: {
|
||||
model: 'Venue',
|
||||
key: 'id'
|
||||
},
|
||||
onUpdate: 'cascade',
|
||||
onDelete: 'cascade'
|
||||
}
|
||||
}, {
|
||||
charset: 'utf8'
|
||||
});
|
||||
},
|
||||
|
||||
down: function (query, Sequelize) {
|
||||
query.dropTable('Sale');
|
||||
query.dropTable('Item');
|
||||
query.dropTable('Subcategory');
|
||||
query.dropTable('Category');
|
||||
query.dropTable('User');
|
||||
query.dropTable('Measure');
|
||||
query.dropTable('Venue');
|
||||
}
|
||||
};
|
||||
@@ -5,7 +5,7 @@ var path = require("path");
|
||||
var Sequelize = require("sequelize");
|
||||
var env = process.env.NODE_ENV || "development";
|
||||
//var config = require(__dirname + '/../config/config.json')[env];
|
||||
var configDB = require('./../../config/database.js');
|
||||
var configDB = require('./../config/database.js');
|
||||
//var sequelize = new Sequelize(config.database, config.username, config.password, config);
|
||||
var sequelize = new Sequelize(configDB.url);
|
||||
var db = {};
|
||||
@@ -10,9 +10,22 @@ module.exports = function(sequelize, DataTypes) {
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
admin: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
},
|
||||
indexes: [
|
||||
{
|
||||
unique: true,
|
||||
fields: ['login']
|
||||
}
|
||||
]
|
||||
}, {
|
||||
freezeTableName: true, // Model tableName will be the same as the model name
|
||||
//paranoid: true, //Keep deleted data but flag it as deleted
|
||||
comment: "A system user authorized to access and manipulate the application data.",
|
||||
instanceMethods: {
|
||||
generateHash: function(password) {
|
||||
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
|
||||
15
package.json
15
package.json
@@ -14,20 +14,21 @@
|
||||
"ejs": "~2.4.1",
|
||||
"express": "~4.11.1",
|
||||
"express-session": "~1.0.4",
|
||||
"morgan": "~1.5.1",
|
||||
"html": "latest",
|
||||
"method-override": "~1.0.2",
|
||||
"moment": "latest",
|
||||
"morgan": "~1.5.1",
|
||||
"node-phantom": "latest",
|
||||
"nodemailer": "~1.0",
|
||||
"passport": "^0.3.2",
|
||||
"passport-local": "^1.0.0",
|
||||
"pg": "^4.4.3",
|
||||
"pg-hstore": "^2.3.2",
|
||||
"sequelize": "^3.14.2",
|
||||
"stylus": "~0.42.3",
|
||||
"swig": "~1.4.2",
|
||||
"session-file-store": "~0.0.24",
|
||||
"sequelize": "^3.0",
|
||||
"sequelize-cli": "^2.4.0",
|
||||
"serve-favicon": "~2.2.0",
|
||||
"nodemailer": "~1.0",
|
||||
"node-phantom": "latest"
|
||||
"session-file-store": "~0.0.24",
|
||||
"stylus": "~0.42.3",
|
||||
"swig": "~1.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
photos/Sarah.JPG
Normal file
BIN
photos/Sarah.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 275 KiB |
BIN
public/VAP_Availability_List_5-2016.pdf
Normal file
BIN
public/VAP_Availability_List_5-2016.pdf
Normal file
Binary file not shown.
@@ -8,7 +8,7 @@
|
||||
<p>Our farm-made fare is created in our commercial kitchen from produce we grow on our farm. We purchase only what we haven't yet figured out how to grow (sugar, flour, salt, etc.). Our labels note which ingredients come from our farm. We save seeds and dry herbs, peppers, tomatoes, tomatillos and fruit for spicing and flavoring.</p>
|
||||
<p>Production changes frequently based on the seasonal harvest, and every run is unique and small scale which means the availability changes regularly. The following PDF download is a current listing of what we offer along with prices.</p>
|
||||
</div>
|
||||
<div style="font-size: .7em; text-align: center; margin-bottom: 40px;"><a href="VAP_Availability_List_4-2016.pdf" download="Petit Teton Farm VAP Availability List.pdf"><img class="priceList" src="images/PriceList_v1.jpg"/><br/>Click to download the price list PDF.</a></div>
|
||||
<div style="font-size: .7em; text-align: center; margin-bottom: 40px;"><a href="VAP_Availability_List_5-2016.pdf" download="Petit Teton Farm VAP Availability List.pdf"><img class="priceList" src="images/PriceList_v1.jpg"/><br/>Click to download the price list PDF.</a></div>
|
||||
<!--
|
||||
<div class="columned" style="margin: 0 auto;">
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div id="grow-and-can" class="page">
|
||||
<h2>“We grow it. We can it.”</h2>
|
||||
<h3>Why this is our motto. What makes it important - to us & to you.<br/>How it came about.</h3>
|
||||
<h3>Why this is our motto. What makes it important - to us & to you.<br/>How it came about.</h3>
|
||||
<p>In the beginning of our farming life it quickly became clear that we produced far more than we consumed so we started selling fresh fruit, produce and eggs at farmers’ markets. There it quickly became apparent that we couldn’t sell everything we grew nor could we sustain a business on what we did sell. We next built a commercial kitchen on the farm to be able to preserve and add value to what we couldn’t eat or sell. Our mantra has always been “NO WASTE”.
|
||||
<p>The fact that we grow everything we preserve sets us apart from most value added product producers and defines our business since most canners purchase their ingredients. It also gives us control of the quality of our canned goods. Although the farm is not certified organic we use only organic practices and as few outside “inputs” as possible which are organic also, eg: incidental flavorings such as spices we cannot grow and necessary preservatives like sugar, vinegar and lemon juice (needed to ensure acidity). A new California law requires that farmers’ markets be divided into two sections - agricultural products and crafts - so the other advantage to growing what we preserve is that we remain in the agricultural section. The canners who do not grow the produce they put in their jars are in the craft section.
|
||||
<p>The art of canning has been honed in families for generations as a way to preserve the summer harvest for winter consumption. This is where we’ve kept it. Our family harvests, selects, hand cuts and cans the produce contained in our jars. There is no machinery or assembly line. All the work is done as you would do it in your kitchen…by hand. And all the food is preserved as it comes in from the fields. Each run of each item is only as large as the amount of the fruit or vegetable harvested that season from our six acres of fields and our aquaponic system.
|
||||
<p>The art of farming, which has been practiced since time immemorial, demands diversity, resilience, self-reliance and creativity. Each year is different and each crop responds differently each year. One must be ready for some to fail and some to succeed and be flexible enough to take advantage of the successes and ride out the failures. This is where the “art” of what we are doing comes into play…if you have 50lbs of mint, what to do? Make mint jelly and pesto. Once the seeds are removed from the blackberries used for jam, soak them and make wine. We use what is available as creatively as we can. And what can’t be preserved is used by the plants and animals and compost. Nothing is wasted.
|
||||
<p>The goal is to create an ever widening circle or spiral of connections and you, the consumer, are part of that circle. We welcome visitors to the farm and are happy to talk and answer questions. You have the freedom to wander and question to certify for yourselves that we are who we say we are, and that the food is what we say it is.
|
||||
<p>The fact that we grow everything we preserve sets us apart from most value added product producers and defines our business since most canners purchase their ingredients. It also gives us control of the quality of our canned goods. Although the farm is not certified organic we use only organic practices and as few outside “inputs” as possible, also organic, eg: incidental flavorings such as spices we cannot grow and necessary preservatives like sugar and vinegar and lemon juice (needed to ensure acidity). A new California law requires that farmers’ markets be divided into two sections - agricultural products and crafts - so the other advantage to growing what we preserve is that we remain in the agricultural section. The canners who do not grow the produce they put in their jars are in the craft section.
|
||||
<p>The art of canning has been honed by families for generations as a way to preserve the summer harvest for winter consumption. This is where we’ve kept it. Our family (we consider anyone working with us “family”) harvests, selects, hand cuts and cans the produce contained in our jars. There is no big machinery or assembly line. The work is done as you would do it in your kitchen…by hand…and the food is preserved as it comes in from the fields. Each run of each item is unique and only as large as the amount of fruit or vegetable harvested that season from our six acres of fields and our aquaponic system.
|
||||
<p>The art of farming, which has been practiced since time immemorial, demands diversity, resilience, self-reliance and creativity. Each year is different and each crop responds differently each year. One must be ready for some to fail and some to succeed beyond expectations, and be flexible enough to take advantage of the successes and ride out the failures. This is where the “art” of what we are doing comes into play…if you have 50lbs of mint, what to do? Make mint jelly and mint pesto. A box of pears starts to ferment - make pear wine. We use what is available as creatively as we can. And what can’t be preserved is used by the plants and animals and compost. Nothing is wasted.
|
||||
<p>The goal is to create an ever widening circle or spiral of connections and you, the consumer, are part of that circle. We welcome visitors to the farm and are happy to talk and answer questions. You have the freedom to wander, question and certify for yourselves that we are who we say we are and that the food is what we say it is. The farm is also diverse, beautiful and full of life.
|
||||
</div>
|
||||
|
||||
BIN
public/images/Us_Sarah_v2.jpg
Normal file
BIN
public/images/Us_Sarah_v2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
@@ -12,7 +12,7 @@
|
||||
<b>Cam</b> has a background in finance, and is a member of the CFA Society of SF. He splits his time between the farm and the city. On farm he's involved in most aspects of the business: planning, planting, harvesting, pruning, water systems, landscaping, kitchen work, and all general back-breaking labor. Most Sundays he can be found at our farm booth at the <a href="#!/markets">Clement Street Farmers' Market</a>.
|
||||
<br/><br/></p>
|
||||
|
||||
<p><img src="images/Us_Sarah_v1.jpg" alt="" border="0" style="float: right; padding: 4px 0px 10px 10px;" align="right"/>
|
||||
<p><img src="images/Us_Sarah_v2.jpg" alt="" border="0" style="float: right; padding: 4px 0px 10px 10px; width: 185px;" align="right"/>
|
||||
<b>Sarah</b> has an business degree and is our kitchen manager. She produces most of our <a href="#!/farm-made-fare">canned and prepared foods</a> and keeps track of them. She loves living in northern California and in the Anderson Valley for its small town feel. Always interested in baking, she's incorporated our home-grown produce into tasty pretzels and other baked goods, which are a big hit on market days during the winter months.</p>
|
||||
<br/>
|
||||
|
||||
|
||||
10
server.js
10
server.js
@@ -20,9 +20,9 @@ var favicon = require('serve-favicon');
|
||||
var nodeMailer = require('nodemailer');
|
||||
//var configDB = require('./config/database.js');
|
||||
var config = require('./config');
|
||||
var models = require("./app/models");
|
||||
var models = require("./models");
|
||||
|
||||
models.sequelize.sync().then(function () {
|
||||
//models.sequelize.sync().then(function () {
|
||||
//SMTP Transport setup.
|
||||
var smtpTransport = nodeMailer.createTransport({host: config.smtpHost, port: config.smtpPort, secure: true, ignoreTLS: false, requiresAuth: true, auth: {user: config.smtpUser, pass: config.smtpPassword}});
|
||||
|
||||
@@ -82,8 +82,8 @@ models.sequelize.sync().then(function () {
|
||||
console.log('The magic happens on port ' + port);
|
||||
console.log("Root Path: " + rootPath);
|
||||
console.log("Time now is: " + moment(new Date()).format("MMM Do YYYY, h:mm:ss a"));
|
||||
}).error(function(err) {
|
||||
console.log("Couldn't create or initialize the database:" + err);
|
||||
})
|
||||
//}).error(function(err) {
|
||||
// console.log("Couldn't create or initialize the database:" + err);
|
||||
//})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user