From 6c17639e0c2c237c88f85f1f5e7c0b9df54fe853 Mon Sep 17 00:00:00 2001 From: Wynne Crisman Date: Sun, 31 Dec 2017 14:06:46 -0800 Subject: [PATCH] Upgraded to Meteor 1.6.0.1 and NodeJS 8.9.3. Added weekly/daily property to venues to support graphing and tracking of actual income from farmers markets (they don't usually match with expected income). Added workers objects to help illustrate who did what work (who was at the market on a specific week for example, or who prep'd and who canned a batch of jam). Fixed some bugs in the venue page. Re-design of the menu to allow for more menu options. --- .meteor/packages | 20 +- .meteor/release | 2 +- .meteor/versions | 76 +- client/client.js | 2 +- client/main.styl | 3 +- imports/api/Measure.js | 2 +- imports/api/Venue.js | 52 +- imports/api/Worker.js | 125 ++ imports/api/index.js | 3 +- imports/startup/both/accounts.js | 28 +- imports/startup/client/routes.js | 7 + imports/ui/Measures.html | 2 +- imports/ui/Venues.html | 13 +- imports/ui/Venues.import.styl | 7 +- imports/ui/Venues.js | 16 +- imports/ui/Workers.html | 90 ++ imports/ui/Workers.import.styl | 145 ++ imports/ui/Workers.js | 237 +++ imports/ui/accounts/accounts.html | 109 +- imports/ui/accounts/accounts.js | 7 + imports/ui/layouts/Body.html | 83 +- imports/ui/layouts/Body.import.styl | 18 +- imports/ui/layouts/Body.js | 47 +- imports/ui/layouts/Full.html | 7 - imports/ui/layouts/Full.import.styl | 11 - imports/ui/layouts/Full.js | 1 - imports/ui/layouts/Login.html | 8 + imports/ui/layouts/Login.import.styl | 64 + imports/ui/layouts/Login.js | 1 + imports/util/de.combo.js | 79 +- package-lock.json | 2036 ++++++++++++++++++++++++++ 31 files changed, 3082 insertions(+), 219 deletions(-) create mode 100644 imports/api/Worker.js create mode 100644 imports/ui/Workers.html create mode 100644 imports/ui/Workers.import.styl create mode 100644 imports/ui/Workers.js delete mode 100644 imports/ui/layouts/Full.html delete mode 100644 imports/ui/layouts/Full.import.styl delete mode 100644 imports/ui/layouts/Full.js create mode 100644 imports/ui/layouts/Login.html create mode 100644 imports/ui/layouts/Login.import.styl create mode 100644 imports/ui/layouts/Login.js create mode 100644 package-lock.json diff --git a/.meteor/packages b/.meteor/packages index bea91c2..34df9ad 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -4,27 +4,27 @@ # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. -meteor-base@1.1.0 # Packages every Meteor app needs to have +meteor-base@1.2.0 # Packages every Meteor app needs to have mobile-experience@1.0.5 # Packages for a great mobile UX -mongo@1.2.2 # The database Meteor supports right now +mongo@1.3.1 # The database Meteor supports right now blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views reactive-var@1.0.11 # Reactive variable for tracker -reactive-dict@1.1.9 # ??? +reactive-dict@1.2.0 # ??? tracker@1.1.3 # Meteor's client-side reactive programming library tomwasd:history-polyfill # Adds IE 8/9 support for HTML5 history. email@1.2.3 # Adds the Meteor/Email package for sending lost password emails standard-minifier-css@1.3.5 # CSS minifier run for production mode -standard-minifier-js@2.1.2 # JS minifier run for production mode +standard-minifier-js@2.2.0 # JS minifier run for production mode es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers. poorvavyas:es6-shim -ecmascript@0.8.3 # Enable ECMAScript2015+ syntax in app code +ecmascript@0.9.0 # Enable ECMAScript2015+ syntax in app code #accounts-ui #accounts-base -accounts-password@1.4.0 +accounts-password@1.5.0 useraccounts:core -useraccounts:bootstrap +useraccounts:unstyled useraccounts:flow-routing # Configures email flows. Used for AccountsTemplates class. alanning:roles # Adds roles to the user mix. https://atmospherejs.com/alanning/roles && https://github.com/alanning/meteor-roles/blob/master/examples/flow-router/ @@ -33,9 +33,9 @@ arillo:flow-router-helpers # Provides various template helpers such as {{pathFo #tomwasd:flow-router-seo kadira:blaze-layout -shell-server@0.2.4 # ??? +shell-server@0.3.0 # ??? meteortoys:allthings -stylus@2.513.9 +stylus@2.513.13 session@1.1.7 ##browser-policy # Adds support for specifying browser level security rules related to content and what's allowed to laod on the page. check@1.2.5 # Allows for checking the structure and types of arguments passed to Meteor methods and publications. @@ -61,6 +61,6 @@ juliancwirko:s-alert # Client error/alert handling jcbernack:reactive-aggregate # Allows us to create a new client collection (from the server) with the contents being an aggregate of server data. Note that aggregation can only be done on the server currently as mini-mongo does not support it. ostrio:logger ostrio:loggermongo -dynamic-import@0.1.3 +dynamic-import@0.2.0 markdown@1.0.12 wcrisman:jquery-custom-scrollbar diff --git a/.meteor/release b/.meteor/release index 099d5b9..56a7a07 100644 --- a/.meteor/release +++ b/.meteor/release @@ -1 +1 @@ -METEOR@1.5.2.2 +METEOR@1.6.0.1 diff --git a/.meteor/versions b/.meteor/versions index 979e17b..aaee1f4 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -1,5 +1,5 @@ -accounts-base@1.3.4 -accounts-password@1.4.0 +accounts-base@1.4.0 +accounts-password@1.5.0 alanning:roles@1.2.16 aldeed:collection2@2.10.0 aldeed:collection2-core@1.2.0 @@ -7,35 +7,35 @@ aldeed:schema-deny@1.1.0 aldeed:schema-index@1.1.1 aldeed:simple-schema@1.5.3 aldeed:template-extension@4.1.0 -allow-deny@1.0.9 +allow-deny@1.1.0 arillo:flow-router-helpers@0.5.2 autoupdate@1.3.12 -babel-compiler@6.20.0 -babel-runtime@1.0.1 +babel-compiler@6.24.7 +babel-runtime@1.1.1 base64@1.0.10 binary-heap@1.0.10 blaze@2.3.2 blaze-html-templates@1.1.2 blaze-tools@1.0.10 -boilerplate-generator@1.2.0 +boilerplate-generator@1.3.1 caching-compiler@1.1.9 caching-html-compiler@1.1.2 callback-hook@1.0.10 check@1.2.5 coffeescript@1.0.17 -ddp@1.3.1 -ddp-client@2.1.3 -ddp-common@1.2.9 +ddp@1.4.0 +ddp-client@2.2.0 +ddp-common@1.3.0 ddp-rate-limiter@1.0.7 -ddp-server@2.0.2 +ddp-server@2.1.1 deps@1.0.12 diff-sequence@1.0.7 -dynamic-import@0.1.3 -ecmascript@0.8.3 -ecmascript-runtime@0.4.1 -ecmascript-runtime-client@0.4.3 -ecmascript-runtime-server@0.4.1 -ejson@1.0.14 +dynamic-import@0.2.1 +ecmascript@0.9.0 +ecmascript-runtime@0.5.0 +ecmascript-runtime-client@0.5.0 +ecmascript-runtime-server@0.5.0 +ejson@1.1.0 email@1.2.3 es5-shim@4.6.15 fortawesome:fontawesome@4.7.0 @@ -43,7 +43,7 @@ geojson-utils@1.0.10 hot-code-push@1.0.4 html-tools@1.0.11 htmljs@1.0.11 -http@1.2.12 +http@1.3.0 id-map@1.0.9 jcbernack:reactive-aggregate@0.7.0 jquery@1.11.10 @@ -52,12 +52,12 @@ kadira:blaze-layout@2.3.0 kadira:flow-router@2.12.1 launch-screen@1.1.1 livedata@1.0.18 -localstorage@1.1.1 -logging@1.1.17 +localstorage@1.2.0 +logging@1.1.19 markdown@1.0.12 mdg:validation-error@0.2.0 -meteor@1.7.2 -meteor-base@1.1.0 +meteor@1.8.2 +meteor-base@1.2.0 meteorhacks:aggregate@1.3.0 meteorhacks:collection-utils@1.2.0 meteortoys:allthings@4.0.0 @@ -78,32 +78,32 @@ meteortoys:throttle@4.0.0 meteortoys:toggle@4.0.0 meteortoys:toykit@4.0.1 minifier-css@1.2.16 -minifier-js@2.1.4 -minimongo@1.3.2 +minifier-js@2.2.2 +minimongo@1.4.3 mizzao:bootboxjs@4.4.0 mobile-experience@1.0.5 mobile-status-bar@1.0.14 -modules@0.10.0 -modules-runtime@0.8.0 -momentjs:moment@2.18.1 -mongo@1.2.2 -mongo-dev-server@1.0.1 +modules@0.11.1 +modules-runtime@0.9.1 +momentjs:moment@2.20.0 +mongo@1.3.1 +mongo-dev-server@1.1.0 mongo-id@1.0.6 mongo-livedata@1.0.12 msavin:jetsetter@4.0.0 msavin:mongol@4.0.1 npm-bcrypt@0.9.3 -npm-mongo@2.2.30 +npm-mongo@2.2.33 observe-sequence@1.0.16 ordered-dict@1.0.9 -ostrio:logger@2.0.3 -ostrio:loggermongo@2.0.1 +ostrio:logger@2.0.5 +ostrio:loggermongo@2.0.3 poorvavyas:es6-shim@0.21.1 -promise@0.9.0 +promise@0.10.0 raix:eventemitter@0.1.3 random@1.0.10 rate-limit@1.0.8 -reactive-dict@1.1.9 +reactive-dict@1.2.0 reactive-var@1.0.11 reload@1.1.11 retry@1.0.9 @@ -111,14 +111,14 @@ routepolicy@1.0.12 service-configuration@1.0.11 session@1.1.7 sha@1.0.9 -shell-server@0.2.4 +shell-server@0.3.1 softwarerero:accounts-t9n@1.3.11 spacebars@1.0.15 spacebars-compiler@1.1.3 srp@1.0.10 standard-minifier-css@1.3.5 -standard-minifier-js@2.1.2 -stylus@2.513.9 +standard-minifier-js@2.2.3 +stylus@2.513.13 templating@1.3.2 templating-compiler@1.3.3 templating-runtime@1.3.2 @@ -128,10 +128,10 @@ tracker@1.1.3 ui@1.0.13 underscore@1.0.10 url@1.1.0 -useraccounts:bootstrap@1.14.2 useraccounts:core@1.14.2 useraccounts:flow-routing@1.14.2 +useraccounts:unstyled@1.14.2 wcrisman:jquery-custom-scrollbar@3.0.0 -webapp@1.3.19 +webapp@1.4.0 webapp-hashing@1.0.9 zimme:active-route@2.3.2 diff --git a/client/client.js b/client/client.js index 8e33b86..b6c437b 100644 --- a/client/client.js +++ b/client/client.js @@ -13,7 +13,7 @@ import '/imports/util/de.combo.js'; import '/imports/util/resize/ResizeSensor.js'; import '/imports/util/resize/ElementQueries.js'; import '/imports/ui/layouts/Body.js'; -import '/imports/ui/layouts/Full.js'; +import '/imports/ui/layouts/Login.js'; import '/imports/ui/accounts/accounts.js'; import '/imports/util/select2/select2.css'; import '/imports/util/select2/select2.full.js'; diff --git a/client/main.styl b/client/main.styl index 001c556..d99e29a 100644 --- a/client/main.styl +++ b/client/main.styl @@ -169,7 +169,7 @@ body @import "../imports/util/bootstrap-like-btn.import.styl" @import "../imports/ui/layouts/Body.import.styl" -@import "../imports/ui/layouts/Full.import.styl" +@import "../imports/ui/layouts/Login.import.styl" @import "../imports/ui/UserManagement.import.styl" @import "../imports/ui/MiscManagement.import.styl" @@ -184,5 +184,6 @@ body @import "../imports/ui/SalesSheetEditor.import.styl" @import "../imports/ui/Pricing.import.styl" @import "../imports/ui/Production.import.styl" +@import "../imports/ui/Workers.import.styl" @import "../imports/ui/Graphs.import.styl" @import "../imports/ui/TestList.import.styl" \ No newline at end of file diff --git a/imports/api/Measure.js b/imports/api/Measure.js index 9ec89a2..847f104 100644 --- a/imports/api/Measure.js +++ b/imports/api/Measure.js @@ -113,7 +113,7 @@ if(Meteor.isServer) { check(order, Number); if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { - Products.update(id, {$set: {name, postfix, order, updatedAt: new Date()}}); + Measures.update(id, {$set: {name, postfix, order, updatedAt: new Date()}}); } else throw new Meteor.Error(403, "Not authorized."); } diff --git a/imports/api/Venue.js b/imports/api/Venue.js index 9e83c80..49557ff 100644 --- a/imports/api/Venue.js +++ b/imports/api/Venue.js @@ -3,6 +3,9 @@ import { Mongo } from 'meteor/mongo'; import { check } from 'meteor/check'; import {SimpleSchema} from 'meteor/aldeed:simple-schema'; +const TYPES = ['Retail', "Farmer's Market", "Restaurant", "Mail"]; +const FREQUENCIES = ['Daily', 'Weekly']; + Venues = new Mongo.Collection('Venues'); let VenuesSchema = new SimpleSchema({ name: { @@ -17,7 +20,15 @@ let VenuesSchema = new SimpleSchema({ type: String, label: "Type", optional: false, - trim: true + trim: true, + allowedValues: TYPES //If you change these values, also change Venues.js for the editor to include the new list when setting up the combo. + }, + frequency: { // How often the market is run. The exact day or week is not important, just that it is daily, weekly, bi-weekly, monthly, etc... Currently only supporting Daily and Weekly since all markets fit into these categories. + type: String, + label: "Frequency", + optional: false, + defaultValue: 'Daily', + allowedValues: FREQUENCIES //If you change these values, also change Venues.js for the editor to include the new list when setting up the combo. }, createdAt: { type: Date, @@ -40,6 +51,7 @@ let VenuesSchema = new SimpleSchema({ optional: true } }); +VenuesSchema.constants = {types: TYPES, frequencies: FREQUENCIES}; Venues.attachSchema(VenuesSchema); if(Meteor.isServer) Meteor.publish('venues', function() { @@ -58,12 +70,30 @@ if(Meteor.isServer) { //}); Meteor.methods({ - createVenue: function(name, type) { + createVenue: function(name, type, frequency) { check(name, String); check(type, String); + check(frequency, String); if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { - Venues.insert({name, type, createdAt: new Date()}); + Venues.insert({name, type, frequency, createdAt: new Date()}); + } + else throw new Meteor.Error(403, "Not authorized."); + }, + //deleteVenue: function(id) { + // if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { + // Venues.remove(id); //TODO: If this is ever allowed, we should either remove or replace references to the deleted venue in the rest of the database. + // } + // else throw new Meteor.Error(403, "Not authorized."); + //}, + updateVenue: function(id, name, type, frequency) { + check(id, String); + check(name, String); + check(type, String); + check(frequency, String); + + if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { + Venues.update(id, {$set: {name, type, frequency, updatedAt: new Date()}}); } else throw new Meteor.Error(403, "Not authorized."); }, @@ -92,22 +122,6 @@ if(Meteor.isServer) { Venues.update(id, {$set: {hidden: false}}, {bypassCollection2: true}); } else throw new Meteor.Error(403, "Not authorized."); - }, - //deleteVenue: function(id) { - // if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { - // Venues.remove(id); //TODO: If this is ever allowed, we should either remove or replace references to the deleted venue in the rest of the database. - // } - // else throw new Meteor.Error(403, "Not authorized."); - //}, - updateVenue: function(id, name, type) { - check(id, String); - check(name, String); - check(type, String); - - if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { - Venues.update(id, {$set: {name, type, updatedAt: new Date()}}); - } - else throw new Meteor.Error(403, "Not authorized."); } }); } diff --git a/imports/api/Worker.js b/imports/api/Worker.js new file mode 100644 index 0000000..7660999 --- /dev/null +++ b/imports/api/Worker.js @@ -0,0 +1,125 @@ +import { Meteor } from 'meteor/meteor'; +import { Mongo } from 'meteor/mongo'; +import { check } from 'meteor/check'; +import {SimpleSchema} from 'meteor/aldeed:simple-schema'; + +Workers = new Mongo.Collection('Workers'); +let WORKER_ACTIVITIES = ['sales', 'prep', 'canning', 'farming']; +let workersSchema = new SimpleSchema({ + name: { + type: String, + label: "Name", + optional: false, + trim: true, + index: 1, + unique: true + }, + activities: { + type: [String], + label: "Activities", + optional: false, + trim: true + }, + hourlyRate: { + type: SimpleSchema.Integer, + label: "HourlyRate", + optional: false, + min: 0 + }, + createdAt: { //Force the value to the current date on the server. + type: Date, + label: "Created On", + // autoValue: function() { //The disadvantage of autoValue is that it sets the date after insertion, causing the UI to update twice - once where the item has no date, and then again where the date is set. Sorted lists will cause the item to bounce around. + // if(this.isInsert) return new Date(); + // else if(this.isUpsert) return {$setOnInsert: new Date()}; + // else this.unset(); + // }, + // denyUpdate: true, + optional: false + }, + updatedAt: { + type: Date, + label: "Updated On", + // autoValue: function() { + // if(this.isUpdate) return new Date(); + // }, + // denyInsert: true, + optional: true + }, + deactivated: { + type: Boolean, + label: "Deactivated", + optional: true + }, + hidden: { + type: Boolean, + label: "Hidden", + optional: true + } +}); +workersSchema.constants = {activities: WORKER_ACTIVITIES}; +Workers.attachSchema(workersSchema); + +if(Meteor.isServer) Meteor.publish('Workers', function() { + return Workers.find({}); +}); + +if(Meteor.isServer) { + Meteor.methods({ + createWorker: function(name, activities, hourlyRate) { + check(name, String); + check(activities, [String]); + check(hourlyRate, Number); + + if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { + Workers.insert({name, activities, hourlyRate, createdAt: new Date()}); + } + else throw new Meteor.Error(403, "Not authorized."); + }, + //deleteWorker: function(id) { + // if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { + // //TODO: Should troll the database looking for references to remove or replace. This is currently not used. + // Workers.remove(id); + // } + // else throw new Meteor.Error(403, "Not authorized."); + //}, + updateWorker: function(id, name, activities, hourlyRate) { + check(id, String); + check(name, String); + check(activities, [String]); + check(hourlyRate, Number); + + if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { + Workers.update(id, {$set: {name, activities, hourlyRate, updatedAt: new Date()}}); + } + else throw new Meteor.Error(403, "Not authorized."); + }, + deactivateWorker: function(id) { + if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { + //Workers.remove(id); + Workers.update(id, {$set: {deactivated: true}}, {bypassCollection2: true}); + } + else throw new Meteor.Error(403, "Not authorized."); + }, + reactivateWorker: function(id) { + if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { + Workers.update(id, {$set: {deactivated: false}}, {bypassCollection2: true}); + } + else throw new Meteor.Error(403, "Not authorized."); + }, + hideWorker: function(id) { //One step past deactivated - will only show in the Workers list if hidden Workers are enabled. + if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { + Workers.update(id, {$set: {hidden: true}}, {bypassCollection2: true}); + } + else throw new Meteor.Error(403, "Not authorized."); + }, + showWorker: function(id) { //Returns the measure to being simply deactivated. Will again show in lists. + if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) { + Workers.update(id, {$set: {hidden: false}}, {bypassCollection2: true}); + } + else throw new Meteor.Error(403, "Not authorized."); + } + }); +} + +export default Workers; \ No newline at end of file diff --git a/imports/api/index.js b/imports/api/index.js index 0821f1e..c46b4ea 100644 --- a/imports/api/index.js +++ b/imports/api/index.js @@ -7,9 +7,10 @@ import SalesSheets from "./SalesSheet.js"; import Logs from "./Logs.js"; import Users from "./User.js"; import UserRoles from "./Roles.js"; +import Workers from "./Worker.js"; //Save the collections in the Meteor.collections property for easy access without name conflicts. -Meteor.collections = {Measures, Venues, Products, ProductTags, Sales, SalesSheets, Logs, Users, UserRoles}; +Meteor.collections = {Measures, Venues, Products, ProductTags, Sales, SalesSheets, Logs, Users, UserRoles, Workers}; //If this is the server then setup the default admin user if none exist. if(Meteor.isServer) { diff --git a/imports/startup/both/accounts.js b/imports/startup/both/accounts.js index 991b959..110eb42 100644 --- a/imports/startup/both/accounts.js +++ b/imports/startup/both/accounts.js @@ -1,16 +1,24 @@ import { AccountsTemplates } from 'meteor/useraccounts:core'; AccountsTemplates.configure({ - forbidClientAccountCreation: true, + forbidClientAccountCreation: true, //Turn off client side account creation. The app is expected to have a feature that will do this. showForgotPasswordLink: true, - defaultTemplate: 'atForm', - defaultLayout: 'Full', - defaultContentRegion: 'content', - defaultLayoutRegions: {} - // defaultTemplate: 'Auth_page', + defaultTemplate: 'OverrideAtForm', + //defaultTemplate: 'AuthorizationPage', //The template for all the forms related to logging in or out. + defaultLayout: 'Login', //What page template to place the defaultTemplate in. + defaultContentRegion: 'content', //The content region of the page template to place the defaultTemplate in. + defaultLayoutRegions: {}, // defaultLayout: 'Body', // defaultContentRegion: 'content', // defaultLayoutRegions: {} + texts: { + title: { + signIn: "" + }, + button: { + signIn: "Enter" + } + } }); // This removes the password field but returns it, @@ -29,6 +37,7 @@ AccountsTemplates.configure({ // pwd // ]); let pwd = AccountsTemplates.removeField('password'); + AccountsTemplates.removeField('email'); AccountsTemplates.addFields([ { @@ -46,6 +55,13 @@ AccountsTemplates.addFields([ re: /.+@(.+){2,}\.(.+){2,}/, errStr: 'Invalid email', }, + { + _id: 'username_and_email', + type: 'text', + required: true, + displayName: "Login", + placeholder: "Login / Email" + }, pwd ]); diff --git a/imports/startup/client/routes.js b/imports/startup/client/routes.js index 28eefcf..929abff 100644 --- a/imports/startup/client/routes.js +++ b/imports/startup/client/routes.js @@ -88,6 +88,13 @@ pri.route('/venues', { BlazeLayout.render('Body', {content: 'Venues'}); } }); +pri.route('/workers', { + name: 'Workers', + action: function(params, queryParams) { + require("/imports/ui/Workers.js"); + BlazeLayout.render('Body', {content: 'Workers'}); + } +}); pri.route('/graphs', { name: 'Graphs', action: function(params, queryParams) { diff --git a/imports/ui/Measures.html b/imports/ui/Measures.html index 28d4ec1..125836c 100644 --- a/imports/ui/Measures.html +++ b/imports/ui/Measures.html @@ -71,7 +71,7 @@
-  /  +  /