<commit_before>"use strict";

var ObjectId = require("mongodb").ObjectId;
require("mongodb-toolkit");
var DLModels = require("dl-models");
var map = DLModels.map;
var PurchaseRequest = DLModels.purchasing.PurchaseRequest;
var generateCode = require("../../utils/code-generator");
var BaseManager = require("module-toolkit").BaseManager;
var i18n = require("dl-i18n");
var UnitManager = require("../master/unit-manager");
var BudgetManager = require("../master/budget-manager");
var CategoryManager = require("../master/category-manager");
var ProductManager = require("../master/product-manager");
var prStatusEnum = DLModels.purchasing.enum.PurchaseRequestStatus;

module.exports = class PurchaseRequestManager extends BaseManager {
    constructor(db, user) {
        super(db, user);
        this.moduleId = "PR";
        this.year = (new Date()).getFullYear().toString().substring(2, 4);
        this.collection = this.db.use(map.purchasing.collection.PurchaseRequest);

        this.unitManager = new UnitManager(db, user);
        this.budgetManager = new BudgetManager(db, user);
        this.categoryManager = new CategoryManager(db, user);
        this.productManager = new ProductManager(db, user);
    }

    _getQuery(paging) {

        var _default = {
            _deleted: false
        },
            pagingFilter = paging.filter || {},
            keywordFilter = {},
            query = {};

        if (paging.keyword) {
            var regex = new RegExp(paging.keyword, "i");
            var filterNo = {
                "no": {
                    "$regex": regex
                }
            };

            var filterUnitDivisionName = {
                "unit.division.name": {
                    "$regex": regex
                }
            };
            var filterUnitName = {
                "unit.name": {
                    "$regex": regex
                }
            };

            var filterCategory = {
                "category.name": {
                    "$regex": regex
                }
            };
            keywordFilter['$or'] = [filterNo, filterUnitDivisionName, filterUnitName, filterCategory];
        }
        query["$and"] = [_default, keywordFilter, pagingFilter];
        return query;
    }

    _validate(purchaseRequest) {
        var errors = {};
        var valid = purchaseRequest;

        var getPurchaseRequestPromise = this.collection.singleOrDefault({
            _id: {
                '$ne': new ObjectId(valid._id)
            },
            no: valid.no
        });

        var getUnit = ObjectId.isValid(valid.unitId) ? this.unitManager.getSingleByIdOrDefault(new ObjectId(valid.unitId)) : Promise.resolve(null);
        var getCategory = ObjectId.isValid(valid.categoryId) ? this.categoryManager.getSingleByIdOrDefault(new ObjectId(valid.categoryId)) : Promise.resolve(null);
        var getBudget = ObjectId.isValid(valid.budgetId) ? this.budgetManager.getSingleByIdOrDefault(new ObjectId(valid.budgetId)) : Promise.resolve(null);

        valid.items = valid.items instanceof Array ? valid.items : [];
        var getProducts = valid.items.map((item) => {
            return ObjectId.isValid(item.productId) ? this.productManager.getSingleByIdOrDefault(new ObjectId(item.productId)) : Promise.resolve(null);
        });

        return Promise.all([getPurchaseRequestPromise, getUnit, getCategory, getBudget].concat(getProducts))
            .then(results => {
                var _purchaseRequest = results[0];
                var _unit = results[1];
                var _category = results[2];
                var _budget = results[3];
                var _products = results.slice(4, results.length);

                if (_purchaseRequest)
                    errors["no"] = i18n.__("PurchaseRequest.no.isExists:%s is exists", i18n.__("PurchaseRequest.product._:No"));

                if (!valid.date || valid.date == "" || valid.date == "undefined")
                    errors["date"] = i18n.__("PurchaseRequest.date.isRequired:%s is required", i18n.__("PurchaseRequest.date._:Date")); //"Tanggal PR tidak boleh kosong";

                if (!_unit)
                    errors["unit"] = i18n.__("PurchaseRequest.unit.isRequired:%s is not exists", i18n.__("PurchaseRequest.unit._:Unit")); //"Unit tidak boleh kosong";
                else if (!valid.unitId)
                    errors["unit"] = i18n.__("PurchaseRequest.unit.isRequired:%s is required", i18n.__("PurchaseRequest.unit._:Unit")); //"Unit tidak boleh kosong";

                if (!_category)
                    errors["category"] = i18n.__("PurchaseRequest.category.isRequired:%s is not exists", i18n.__("PurchaseRequest.category._:Category")); //"Category tidak boleh kosong";
                else if (!valid.categoryId)
                    errors["category"] = i18n.__("PurchaseRequest.category.isRequired:%s is required", i18n.__("PurchaseRequest.category._:Category")); //"Category tidak boleh kosong";

                if (!_budget)
                    errors["budget"] = i18n.__("PurchaseRequest.budget.name.isRequired:%s is not exists", i18n.__("PurchaseRequest.budget.name._:Budget")); //"Budget tidak boleh kosong";
                else if (!valid.budget._id)
                    errors["budget"] = i18n.__("PurchaseRequest.budget.name.isRequired:%s is required", i18n.__("PurchaseRequest.budget.name._:Budget")); //"Budget tidak boleh kosong";

                if (!valid.expectedDeliveryDate || valid.expectedDeliveryDate === "" || valid.expectedDeliveryDate === "undefined")
                    valid.expectedDeliveryDate = "";

                if (valid.items && valid.items.length <= 0) {
                    errors["items"] = i18n.__("PurchaseRequest.items.isRequired:%s is required", i18n.__("PurchaseRequest.items._:Item")); //"Harus ada minimal 1 barang";
                }
                else {
                    var itemErrors = [];
                    var valueArr = valid.items.map(function (item) { return item.productId.toString() });
                    var isDuplicate = valueArr.some(function (item, idx) {
                        var itemError = {};
                        if (valueArr.indexOf(item) != idx) {
                            itemError["product"] = i18n.__("PurchaseRequest.items.product.name.isDuplicate:%s is duplicate", i18n.__("PurchaseRequest.items.product.name._:Name")); //"Nama barang tidak boleh kosong";
                        }
                        if (Object.getOwnPropertyNames(itemError).length > 0) {
                            itemErrors[valueArr.indexOf(item)]= itemError;
                            itemErrors[idx]= itemError;
                        }
                        return valueArr.indexOf(item) != idx
                    });
                    if (!isDuplicate) {
                        for (var item of valid.items) {
                            var itemError = {};
                            if (!item.product || !item.product._id) {
                                itemError["product"] = i18n.__("PurchaseRequest.items.product.name.isRequired:%s is required", i18n.__("PurchaseRequest.items.product.name._:Name")); //"Nama barang tidak boleh kosong";
                            }
                            if (item.quantity <= 0) {
                                itemError["quantity"] = i18n.__("PurchaseRequest.items.quantity.isRequired:%s is required", i18n.__("PurchaseRequest.items.quantity._:Quantity")); //Jumlah barang tidak boleh kosong";
                            }
                            if (Object.getOwnPropertyNames(itemError).length > 0) {
                                itemErrors.push(itemError);
                            }
                        }
                    }
                    if (itemErrors.length > 0)
                        errors.items = itemErrors;
                }

                if (Object.getOwnPropertyNames(errors).length > 0) {
                    var ValidationError = require("module-toolkit").ValidationError;
                    return Promise.reject(new ValidationError("data does not pass validation", errors));
                }

                valid.unitId = _unit._id;
                valid.unit = _unit;

                valid.categoryId = _category._id;
                valid.category = _category;

                valid.budgetId = _budget._id;
                valid.budget = _budget;

                valid.date = new Date(valid.date);
                valid.expectedDeliveryDate = new Date(valid.expectedDeliveryDate);

                for (var prItem of valid.items) {
                    for (var _product of _products) {
                        if (prItem.product._id.toString() === _product._id.toString()) {
                            prItem.productId = _product._id;
                            prItem.product = _product;
                            prItem.uom = _product.uom;
                            break;
                        }
                    }
                }

                if (!valid.stamp)
                    valid = new PurchaseRequest(valid);

                valid.stamp(this.user.username, "manager");
                return Promise.resolve(valid);
            });
    }

    _beforeInsert(purchaseRequest) {
        purchaseRequest.no = generateCode();
        purchaseRequest.status = prStatusEnum.CREATED;
        return Promise.resolve(purchaseRequest);
    }

    post(listPurchaseRequest) {
        var purchaseRequests = [];
        var tasks = [];
        return new Promise((resolve, reject) => {
            for (var purchaseRequest of listPurchaseRequest) {
                purchaseRequests.push(this.getSingleByIdOrDefault(purchaseRequest._id));
            }
            Promise.all(purchaseRequests)
                .then(validPurchaseRequest => {
                    for (var pr of listPurchaseRequest) {
                        for (var _pr of validPurchaseRequest) {
                            if (_pr._id.equals(pr._id)) {
                                _pr.isPosted = true;
                                _pr.status = prStatusEnum.POSTED;
                                tasks.push(this.update(_pr));
                                break;
                            }
                        }

                    }
                    Promise.all(tasks)
                        .then(result => {
                            resolve(result);
                        })
                        .catch(e => {
                            reject(e);
                        });

                })
                .catch(e => {
                    reject(e);
                });
        });

    }

    pdf(id) {
        return new Promise((resolve, reject) => {

            this.getSingleById(id)
                .then(purchaseRequest => {
                    var getDefinition = require("../../pdf/definitions/purchase-request");
                    var definition = getDefinition(purchaseRequest);

                    var generatePdf = require("../../pdf/pdf-generator");
                    generatePdf(definition)
                        .then(binary => {
                            resolve(binary);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });

        });
    }

    getDataPRMonitoring(unitId, categoryId, budgetId, PRNo, dateFrom, dateTo, state) {
        return new Promise((resolve, reject) => {
            var sorting = {
                "date": -1,
                "no": 1
            };
            var query = Object.assign({});

            if (state !== -1) {
                Object.assign(query, {
                    "status.value": state
                });
            }

            if (unitId !== "undefined" && unitId !== "") {
                Object.assign(query, {
                    unitId: new ObjectId(unitId)
                });
            }
            if (categoryId !== "undefined" && categoryId !== "") {
                Object.assign(query, {
                    categoryId: new ObjectId(categoryId)
                });
            }
            if (budgetId !== "undefined" && budgetId !== "") {
                Object.assign(query, {
                    budgetId: new ObjectId(budgetId)
                });
            }
            if (PRNo !== "undefined" && PRNo !== "") {
                Object.assign(query, {
                    "no": PRNo
                });
            }
            if (dateFrom !== "undefined" && dateFrom !== "" && dateFrom !== "null" && dateTo !== "undefined" && dateTo !== "" && dateTo !== "null") {
                Object.assign(query, {
                    date: {
                        $gte: new Date(dateFrom),
                        $lte: new Date(dateTo)
                    }
                });
            }
            query = Object.assign(query, {
                _createdBy: this.user.username,
                _deleted: false,
                isPosted: true
            });

            this.collection.find(query).sort(sorting).toArray()
                .then((purchaseRequests) => {
                    resolve(purchaseRequests);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getDataPRMonitoringAllUser(unitId, categoryId, budgetId, PRNo, dateFrom, dateTo, state) {
        return new Promise((resolve, reject) => {
            var sorting = {
                "date": -1,
                "no": 1
            };
            var query = Object.assign({});

            if (state !== -1) {
                Object.assign(query, {
                    "status.value": state
                });
            }

            if (unitId !== "undefined" && unitId !== "") {
                Object.assign(query, {
                    unitId: new ObjectId(unitId)
                });
            }
            if (categoryId !== "undefined" && categoryId !== "") {
                Object.assign(query, {
                    categoryId: new ObjectId(categoryId)
                });
            }
            if (budgetId !== "undefined" && budgetId !== "") {
                Object.assign(query, {
                    budgetId: new ObjectId(budgetId)
                });
            }
            if (PRNo !== "undefined" && PRNo !== "") {
                Object.assign(query, {
                    "no": PRNo
                });
            }
            if (dateFrom !== "undefined" && dateFrom !== "" && dateFrom !== "null" && dateTo !== "undefined" && dateTo !== "" && dateTo !== "null") {
                Object.assign(query, {
                    date: {
                        $gte: new Date(dateFrom),
                        $lte: new Date(dateTo)
                    }
                });
            }
            query = Object.assign(query, {
                _deleted: false,
                isPosted: true
            });

            this.collection.find(query).sort(sorting).toArray()
                .then((purchaseRequests) => {
                    resolve(purchaseRequests);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    _createIndexes() {
        var dateIndex = {
            name: `ix_${map.purchasing.collection.PurchaseRequest}__updatedDate`,
            key: {
                _updatedDate: -1
            }
        };

        var noIndex = {
            name: `ix_${map.purchasing.collection.PurchaseRequest}_no`,
            key: {
                no: 1
            },
            unique: true
        };

        return this.collection.createIndexes([dateIndex, noIndex]);
    }
};<commit_msg>add validation items<commit_after>"use strict";

var ObjectId = require("mongodb").ObjectId;
require("mongodb-toolkit");
var DLModels = require("dl-models");
var map = DLModels.map;
var PurchaseRequest = DLModels.purchasing.PurchaseRequest;
var generateCode = require("../../utils/code-generator");
var BaseManager = require("module-toolkit").BaseManager;
var i18n = require("dl-i18n");
var UnitManager = require("../master/unit-manager");
var BudgetManager = require("../master/budget-manager");
var CategoryManager = require("../master/category-manager");
var ProductManager = require("../master/product-manager");
var prStatusEnum = DLModels.purchasing.enum.PurchaseRequestStatus;

module.exports = class PurchaseRequestManager extends BaseManager {
    constructor(db, user) {
        super(db, user);
        this.moduleId = "PR";
        this.year = (new Date()).getFullYear().toString().substring(2, 4);
        this.collection = this.db.use(map.purchasing.collection.PurchaseRequest);

        this.unitManager = new UnitManager(db, user);
        this.budgetManager = new BudgetManager(db, user);
        this.categoryManager = new CategoryManager(db, user);
        this.productManager = new ProductManager(db, user);
    }

    _getQuery(paging) {

        var _default = {
            _deleted: false
        },
            pagingFilter = paging.filter || {},
            keywordFilter = {},
            query = {};

        if (paging.keyword) {
            var regex = new RegExp(paging.keyword, "i");
            var filterNo = {
                "no": {
                    "$regex": regex
                }
            };

            var filterUnitDivisionName = {
                "unit.division.name": {
                    "$regex": regex
                }
            };
            var filterUnitName = {
                "unit.name": {
                    "$regex": regex
                }
            };

            var filterCategory = {
                "category.name": {
                    "$regex": regex
                }
            };
            keywordFilter['$or'] = [filterNo, filterUnitDivisionName, filterUnitName, filterCategory];
        }
        query["$and"] = [_default, keywordFilter, pagingFilter];
        return query;
    }

    _validate(purchaseRequest) {
        var errors = {};
        var valid = purchaseRequest;

        var getPurchaseRequestPromise = this.collection.singleOrDefault({
            _id: {
                '$ne': new ObjectId(valid._id)
            },
            no: valid.no
        });

        var getUnit = ObjectId.isValid(valid.unitId) ? this.unitManager.getSingleByIdOrDefault(new ObjectId(valid.unitId)) : Promise.resolve(null);
        var getCategory = ObjectId.isValid(valid.categoryId) ? this.categoryManager.getSingleByIdOrDefault(new ObjectId(valid.categoryId)) : Promise.resolve(null);
        var getBudget = ObjectId.isValid(valid.budgetId) ? this.budgetManager.getSingleByIdOrDefault(new ObjectId(valid.budgetId)) : Promise.resolve(null);

        valid.items = valid.items instanceof Array ? valid.items : [];
        var getProducts = valid.items.map((item) => {
            return ObjectId.isValid(item.productId) ? this.productManager.getSingleByIdOrDefault(new ObjectId(item.productId)) : Promise.resolve(null);
        });

        return Promise.all([getPurchaseRequestPromise, getUnit, getCategory, getBudget].concat(getProducts))
            .then(results => {
                var _purchaseRequest = results[0];
                var _unit = results[1];
                var _category = results[2];
                var _budget = results[3];
                var _products = results.slice(4, results.length);

                if (_purchaseRequest)
                    errors["no"] = i18n.__("PurchaseRequest.no.isExists:%s is exists", i18n.__("PurchaseRequest.product._:No"));

                if (!valid.date || valid.date == "" || valid.date == "undefined")
                    errors["date"] = i18n.__("PurchaseRequest.date.isRequired:%s is required", i18n.__("PurchaseRequest.date._:Date")); //"Tanggal PR tidak boleh kosong";

                if (!_unit)
                    errors["unit"] = i18n.__("PurchaseRequest.unit.isRequired:%s is not exists", i18n.__("PurchaseRequest.unit._:Unit")); //"Unit tidak boleh kosong";
                else if (!valid.unitId)
                    errors["unit"] = i18n.__("PurchaseRequest.unit.isRequired:%s is required", i18n.__("PurchaseRequest.unit._:Unit")); //"Unit tidak boleh kosong";

                if (!_category)
                    errors["category"] = i18n.__("PurchaseRequest.category.isRequired:%s is not exists", i18n.__("PurchaseRequest.category._:Category")); //"Category tidak boleh kosong";
                else if (!valid.categoryId)
                    errors["category"] = i18n.__("PurchaseRequest.category.isRequired:%s is required", i18n.__("PurchaseRequest.category._:Category")); //"Category tidak boleh kosong";

                if (!_budget)
                    errors["budget"] = i18n.__("PurchaseRequest.budget.name.isRequired:%s is not exists", i18n.__("PurchaseRequest.budget.name._:Budget")); //"Budget tidak boleh kosong";
                else if (!valid.budget._id)
                    errors["budget"] = i18n.__("PurchaseRequest.budget.name.isRequired:%s is required", i18n.__("PurchaseRequest.budget.name._:Budget")); //"Budget tidak boleh kosong";

                if (!valid.expectedDeliveryDate || valid.expectedDeliveryDate === "" || valid.expectedDeliveryDate === "undefined")
                    valid.expectedDeliveryDate = "";

                if (valid.items && valid.items.length <= 0) {
                    errors["items"] = i18n.__("PurchaseRequest.items.isRequired:%s is required", i18n.__("PurchaseRequest.items._:Item")); //"Harus ada minimal 1 barang";
                }
                else {
                    var itemErrors = [];
                    var valueArr = valid.items.map(function (item) { return item.productId.toString() });
                    var isDuplicate = valueArr.some(function (item, idx) {
                        var itemError = {};
                        if (valueArr.indexOf(item) != idx) {
                            itemError["product"] = i18n.__("PurchaseRequest.items.product.name.isDuplicate:%s is duplicate", i18n.__("PurchaseRequest.items.product.name._:Product")); //"Nama barang tidak boleh kosong";
                        }
                        if (Object.getOwnPropertyNames(itemError).length > 0) {
                            itemErrors[valueArr.indexOf(item)]= itemError;
                            itemErrors[idx]= itemError;
                        }
                        return valueArr.indexOf(item) != idx
                    });
                    if (!isDuplicate) {
                        for (var item of valid.items) {
                            var itemError = {};
                            if (!item.product || !item.product._id) {
                                itemError["product"] = i18n.__("PurchaseRequest.items.product.name.isRequired:%s is required", i18n.__("PurchaseRequest.items.product.name._:Product")); //"Nama barang tidak boleh kosong";
                            }
                            if (item.quantity <= 0) {
                                itemError["quantity"] = i18n.__("PurchaseRequest.items.quantity.isRequired:%s is required", i18n.__("PurchaseRequest.items.quantity._:Quantity")); //Jumlah barang tidak boleh kosong";
                            }
                            if (Object.getOwnPropertyNames(itemError).length > 0) {
                                itemErrors.push(itemError);
                            }
                        }
                    }
                    if (itemErrors.length > 0)
                        errors.items = itemErrors;
                }

                if (Object.getOwnPropertyNames(errors).length > 0) {
                    var ValidationError = require("module-toolkit").ValidationError;
                    return Promise.reject(new ValidationError("data does not pass validation", errors));
                }

                valid.unitId = _unit._id;
                valid.unit = _unit;

                valid.categoryId = _category._id;
                valid.category = _category;

                valid.budgetId = _budget._id;
                valid.budget = _budget;

                valid.date = new Date(valid.date);
                valid.expectedDeliveryDate = new Date(valid.expectedDeliveryDate);

                for (var prItem of valid.items) {
                    for (var _product of _products) {
                        if (prItem.product._id.toString() === _product._id.toString()) {
                            prItem.productId = _product._id;
                            prItem.product = _product;
                            prItem.uom = _product.uom;
                            break;
                        }
                    }
                }

                if (!valid.stamp)
                    valid = new PurchaseRequest(valid);

                valid.stamp(this.user.username, "manager");
                return Promise.resolve(valid);
            });
    }

    _beforeInsert(purchaseRequest) {
        purchaseRequest.no = generateCode();
        purchaseRequest.status = prStatusEnum.CREATED;
        return Promise.resolve(purchaseRequest);
    }

    post(listPurchaseRequest) {
        var purchaseRequests = [];
        var tasks = [];
        return new Promise((resolve, reject) => {
            for (var purchaseRequest of listPurchaseRequest) {
                purchaseRequests.push(this.getSingleByIdOrDefault(purchaseRequest._id));
            }
            Promise.all(purchaseRequests)
                .then(validPurchaseRequest => {
                    for (var pr of listPurchaseRequest) {
                        for (var _pr of validPurchaseRequest) {
                            if (_pr._id.equals(pr._id)) {
                                _pr.isPosted = true;
                                _pr.status = prStatusEnum.POSTED;
                                tasks.push(this.update(_pr));
                                break;
                            }
                        }

                    }
                    Promise.all(tasks)
                        .then(result => {
                            resolve(result);
                        })
                        .catch(e => {
                            reject(e);
                        });

                })
                .catch(e => {
                    reject(e);
                });
        });

    }

    pdf(id) {
        return new Promise((resolve, reject) => {

            this.getSingleById(id)
                .then(purchaseRequest => {
                    var getDefinition = require("../../pdf/definitions/purchase-request");
                    var definition = getDefinition(purchaseRequest);

                    var generatePdf = require("../../pdf/pdf-generator");
                    generatePdf(definition)
                        .then(binary => {
                            resolve(binary);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });

        });
    }

    getDataPRMonitoring(unitId, categoryId, budgetId, PRNo, dateFrom, dateTo, state) {
        return new Promise((resolve, reject) => {
            var sorting = {
                "date": -1,
                "no": 1
            };
            var query = Object.assign({});

            if (state !== -1) {
                Object.assign(query, {
                    "status.value": state
                });
            }

            if (unitId !== "undefined" && unitId !== "") {
                Object.assign(query, {
                    unitId: new ObjectId(unitId)
                });
            }
            if (categoryId !== "undefined" && categoryId !== "") {
                Object.assign(query, {
                    categoryId: new ObjectId(categoryId)
                });
            }
            if (budgetId !== "undefined" && budgetId !== "") {
                Object.assign(query, {
                    budgetId: new ObjectId(budgetId)
                });
            }
            if (PRNo !== "undefined" && PRNo !== "") {
                Object.assign(query, {
                    "no": PRNo
                });
            }
            if (dateFrom !== "undefined" && dateFrom !== "" && dateFrom !== "null" && dateTo !== "undefined" && dateTo !== "" && dateTo !== "null") {
                Object.assign(query, {
                    date: {
                        $gte: new Date(dateFrom),
                        $lte: new Date(dateTo)
                    }
                });
            }
            query = Object.assign(query, {
                _createdBy: this.user.username,
                _deleted: false,
                isPosted: true
            });

            this.collection.find(query).sort(sorting).toArray()
                .then((purchaseRequests) => {
                    resolve(purchaseRequests);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getDataPRMonitoringAllUser(unitId, categoryId, budgetId, PRNo, dateFrom, dateTo, state) {
        return new Promise((resolve, reject) => {
            var sorting = {
                "date": -1,
                "no": 1
            };
            var query = Object.assign({});

            if (state !== -1) {
                Object.assign(query, {
                    "status.value": state
                });
            }

            if (unitId !== "undefined" && unitId !== "") {
                Object.assign(query, {
                    unitId: new ObjectId(unitId)
                });
            }
            if (categoryId !== "undefined" && categoryId !== "") {
                Object.assign(query, {
                    categoryId: new ObjectId(categoryId)
                });
            }
            if (budgetId !== "undefined" && budgetId !== "") {
                Object.assign(query, {
                    budgetId: new ObjectId(budgetId)
                });
            }
            if (PRNo !== "undefined" && PRNo !== "") {
                Object.assign(query, {
                    "no": PRNo
                });
            }
            if (dateFrom !== "undefined" && dateFrom !== "" && dateFrom !== "null" && dateTo !== "undefined" && dateTo !== "" && dateTo !== "null") {
                Object.assign(query, {
                    date: {
                        $gte: new Date(dateFrom),
                        $lte: new Date(dateTo)
                    }
                });
            }
            query = Object.assign(query, {
                _deleted: false,
                isPosted: true
            });

            this.collection.find(query).sort(sorting).toArray()
                .then((purchaseRequests) => {
                    resolve(purchaseRequests);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    _createIndexes() {
        var dateIndex = {
            name: `ix_${map.purchasing.collection.PurchaseRequest}__updatedDate`,
            key: {
                _updatedDate: -1
            }
        };

        var noIndex = {
            name: `ix_${map.purchasing.collection.PurchaseRequest}_no`,
            key: {
                no: 1
            },
            unique: true
        };

        return this.collection.createIndexes([dateIndex, noIndex]);
    }
};<|endoftext|>


<commit_before>/**
  We use this class to track how long posts in a topic are on the screen.

  @class ScreenTrack
  @extends Ember.Object
  @namespace Discourse
  @module Discourse
**/

var PAUSE_UNLESS_SCROLLED = 1000 * 60 * 3,
    MAX_TRACKING_TIME = 1000 * 60 * 6;

Discourse.ScreenTrack = Ember.Object.extend({

  init: function() {
    this.reset();
  },

  start: function(topicId, topicController) {
    var currentTopicId = this.get('topicId');
    if (currentTopicId && (currentTopicId !== topicId)) {
      this.tick();
      this.flush();
    }

    this.reset();

    // Create an interval timer if we don't have one.
    if (!this.get('interval')) {
      var self = this;
      this.set('interval', setInterval(function () {
        self.tick();
      }, 1000));
    }

    this.set('topicId', topicId);
    this.set('topicController', topicController);
  },

  stop: function() {
    if(!this.get('topicId')) {
      // already stopped no need to "extra stop"
      return;
    }

    this.tick();
    this.flush();
    this.reset();
    this.set('topicId', null);
    this.set('topicController', null);
    if (this.get('interval')) {
      clearInterval(this.get('interval'));
      this.set('interval', null);
    }
  },

  track: function(elementId, postNumber) {
    this.get('timings')["#" + elementId] = {
      time: 0,
      postNumber: postNumber
    };
  },

  stopTracking: function(elementId) {
    delete this.get('timings')['#' + elementId];
  },

  // Reset our timers
  reset: function() {
    this.setProperties({
      lastTick: new Date().getTime(),
      lastScrolled: new Date().getTime(),
      lastFlush: 0,
      cancelled: false,
      timings: {},
      totalTimings: {},
      topicTime: 0
    });
  },

  scrolled: function() {
    this.set('lastScrolled', new Date().getTime());
  },

  flush: function() {
    if (this.get('cancelled')) { return; }

    // We don't log anything unless we're logged in
    if (!Discourse.User.current()) return;

    var newTimings = {},
        totalTimings = this.get('totalTimings'),
        self = this;

    _.each(this.get('timings'), function(timing) {
      if (!totalTimings[timing.postNumber])
        totalTimings[timing.postNumber] = 0;

      if (timing.time > 0 && totalTimings[timing.postNumber] < MAX_TRACKING_TIME) {
        totalTimings[timing.postNumber] += timing.time;
        newTimings[timing.postNumber] = timing.time;
      }
      timing.time = 0;
    });

    var topicId = parseInt(this.get('topicId'), 10),
        highestSeen = 0;

    _.each(newTimings, function(time,postNumber) {
      highestSeen = Math.max(highestSeen, parseInt(postNumber, 10));
    });

    var highestSeenByTopic = Discourse.Session.currentProp('highestSeenByTopic');
    if ((highestSeenByTopic[topicId] || 0) < highestSeen) {
      highestSeenByTopic[topicId] = highestSeen;
    }

    Discourse.TopicTrackingState.current().updateSeen(topicId, highestSeen);

    if (!$.isEmptyObject(newTimings)) {
      Discourse.ajax('/topics/timings', {
        data: {
          timings: newTimings,
          topic_time: this.get('topicTime'),
          topic_id: topicId
        },
        cache: false,
        type: 'POST',
        headers: {
          'X-SILENCE-LOGGER': 'true'
        }
      }).then(function(){
        var controller = self.get('topicController');
        if(controller){
          var postNumbers = Object.keys(newTimings).map(function(v){
            return parseInt(v,10);
          });
          controller.readPosts(topicId, postNumbers);
        }
      });

      this.set('topicTime', 0);
    }
    this.set('lastFlush', 0);
  },

  tick: function() {

    // If the user hasn't scrolled the browser in a long time, stop tracking time read
    var sinceScrolled = new Date().getTime() - this.get('lastScrolled');
    if (sinceScrolled > PAUSE_UNLESS_SCROLLED) {
      return;
    }

    var diff = new Date().getTime() - this.get('lastTick');
    this.set('lastFlush', this.get('lastFlush') + diff);
    this.set('lastTick', new Date().getTime());

    var totalTimings = this.get('totalTimings'), timings = this.get('timings');
    var nextFlush = Discourse.SiteSettings.flush_timings_secs * 1000;

    // rush new post numbers
    var rush = _.any(_.filter(timings, function(t){return t.time>0;}), function(t){
      return !totalTimings[t.postNumber];
    });

    if (this.get('lastFlush') > nextFlush || rush) {
      this.flush();
    }

    // Don't track timings if we're not in focus
    if (!Discourse.get("hasFocus")) return;

    this.set('topicTime', this.get('topicTime') + diff);
    var docViewTop = $(window).scrollTop() + $('header').height(),
        docViewBottom = docViewTop + $(window).height();

    // TODO: Eyeline has a smarter more accurate function here. It's bad to do jQuery
    // in a model like component, so we should refactor this out later.
    _.each(this.get('timings'),function(timing,id) {
      var $element = $(id);
      if ($element.length === 1) {
        var elemTop = $element.offset().top,
            elemBottom = elemTop + $element.height();

        // If part of the element is on the screen, increase the counter
        if (((docViewTop <= elemTop && elemTop <= docViewBottom)) || ((docViewTop <= elemBottom && elemBottom <= docViewBottom))) {
          timing.time = timing.time + diff;
        }
      }
    });
  }
});

Discourse.ScreenTrack.reopenClass(Discourse.Singleton);

<commit_msg>BUGFIX: scrolled never ever fired :(<commit_after>/**
  We use this class to track how long posts in a topic are on the screen.

  @class ScreenTrack
  @extends Ember.Object
  @namespace Discourse
  @module Discourse
**/

var PAUSE_UNLESS_SCROLLED = 1000 * 60 * 3,
    MAX_TRACKING_TIME = 1000 * 60 * 6;

Discourse.ScreenTrack = Ember.Object.extend({

  init: function() {
    this.reset();
  },

  start: function(topicId, topicController) {
    var currentTopicId = this.get('topicId');
    if (currentTopicId && (currentTopicId !== topicId)) {
      this.tick();
      this.flush();
    }

    this.reset();

    // Create an interval timer if we don't have one.
    if (!this.get('interval')) {
      var self = this;
      this.set('interval', setInterval(function () {
        self.tick();
      }, 1000));

      $(window).on('scroll.screentrack', function(){self.scrolled()});
    }

    this.set('topicId', topicId);
    this.set('topicController', topicController);
  },

  stop: function() {
    if(!this.get('topicId')) {
      // already stopped no need to "extra stop"
      return;
    }
    $(window).off('scroll.screentrack');
    this.tick();
    this.flush();
    this.reset();
    this.set('topicId', null);
    this.set('topicController', null);
    if (this.get('interval')) {
      clearInterval(this.get('interval'));
      this.set('interval', null);
    }
  },

  track: function(elementId, postNumber) {
    this.get('timings')["#" + elementId] = {
      time: 0,
      postNumber: postNumber
    };
  },

  stopTracking: function(elementId) {
    delete this.get('timings')['#' + elementId];
  },

  // Reset our timers
  reset: function() {
    this.setProperties({
      lastTick: new Date().getTime(),
      lastScrolled: new Date().getTime(),
      lastFlush: 0,
      cancelled: false,
      timings: {},
      totalTimings: {},
      topicTime: 0
    });
  },

  scrolled: function() {
    this.set('lastScrolled', new Date().getTime());
  },

  flush: function() {
    if (this.get('cancelled')) { return; }

    // We don't log anything unless we're logged in
    if (!Discourse.User.current()) return;

    var newTimings = {},
        totalTimings = this.get('totalTimings'),
        self = this;

    _.each(this.get('timings'), function(timing) {
      if (!totalTimings[timing.postNumber])
        totalTimings[timing.postNumber] = 0;

      if (timing.time > 0 && totalTimings[timing.postNumber] < MAX_TRACKING_TIME) {
        totalTimings[timing.postNumber] += timing.time;
        newTimings[timing.postNumber] = timing.time;
      }
      timing.time = 0;
    });

    var topicId = parseInt(this.get('topicId'), 10),
        highestSeen = 0;

    _.each(newTimings, function(time,postNumber) {
      highestSeen = Math.max(highestSeen, parseInt(postNumber, 10));
    });

    var highestSeenByTopic = Discourse.Session.currentProp('highestSeenByTopic');
    if ((highestSeenByTopic[topicId] || 0) < highestSeen) {
      highestSeenByTopic[topicId] = highestSeen;
    }

    Discourse.TopicTrackingState.current().updateSeen(topicId, highestSeen);

    if (!$.isEmptyObject(newTimings)) {
      Discourse.ajax('/topics/timings', {
        data: {
          timings: newTimings,
          topic_time: this.get('topicTime'),
          topic_id: topicId
        },
        cache: false,
        type: 'POST',
        headers: {
          'X-SILENCE-LOGGER': 'true'
        }
      }).then(function(){
        var controller = self.get('topicController');
        if(controller){
          var postNumbers = Object.keys(newTimings).map(function(v){
            return parseInt(v,10);
          });
          controller.readPosts(topicId, postNumbers);
        }
      });

      this.set('topicTime', 0);
    }
    this.set('lastFlush', 0);
  },

  tick: function() {

    // If the user hasn't scrolled the browser in a long time, stop tracking time read
    var sinceScrolled = new Date().getTime() - this.get('lastScrolled');
    if (sinceScrolled > PAUSE_UNLESS_SCROLLED) {
      return;
    }

    var diff = new Date().getTime() - this.get('lastTick');
    this.set('lastFlush', this.get('lastFlush') + diff);
    this.set('lastTick', new Date().getTime());

    var totalTimings = this.get('totalTimings'), timings = this.get('timings');
    var nextFlush = Discourse.SiteSettings.flush_timings_secs * 1000;

    // rush new post numbers
    var rush = _.any(_.filter(timings, function(t){return t.time>0;}), function(t){
      return !totalTimings[t.postNumber];
    });

    if (this.get('lastFlush') > nextFlush || rush) {
      this.flush();
    }

    // Don't track timings if we're not in focus
    if (!Discourse.get("hasFocus")) return;

    this.set('topicTime', this.get('topicTime') + diff);
    var docViewTop = $(window).scrollTop() + $('header').height(),
        docViewBottom = docViewTop + $(window).height();

    // TODO: Eyeline has a smarter more accurate function here. It's bad to do jQuery
    // in a model like component, so we should refactor this out later.
    _.each(this.get('timings'),function(timing,id) {
      var $element = $(id);
      if ($element.length === 1) {
        var elemTop = $element.offset().top,
            elemBottom = elemTop + $element.height();

        // If part of the element is on the screen, increase the counter
        if (((docViewTop <= elemTop && elemTop <= docViewBottom)) || ((docViewTop <= elemBottom && elemBottom <= docViewBottom))) {
          timing.time = timing.time + diff;
        }
      }
    });
  }
});

Discourse.ScreenTrack.reopenClass(Discourse.Singleton);

<|endoftext|>


<commit_before>var bcrypt = require("bcryptjs");
var fs = require('fs');
var child_process = require("child_process");
var spawn = child_process.spawn;

/**
The script can be called with 2 to 4 arguments

SYNOPSIS
	node removeCustomizedElection.js -e ELECTIONID -p PASSWORD [-h]

OPTIONS:
	-e ELECTIONID: the electionID for the election, at least 7 digits of the electionID are required
	-p PASSWORD: the password to remove the election
	[-h]: if the election is hidden, this argument is required to remove it
**/

var passList = JSON.parse(fs.readFileSync("../ElectionHandler/_data_/pwd.json"));

var eleID;
var pass;
var hide = false;
for(var i = 0; i < process.argv.length; i++){
	if(process.argv[i] === '-e'){
		eleID = process.argv[i+1].slice(0,7);
		i++;
	}
	else if(process.argv[i] === '-p'){
		pass = process.argv[i+1];
		i++;
	}
	else if(process.argv[i] === '-h'){
		hide = true;
	}
}

if(!passList.hasOwnProperty(eleID)){
	//means the election already has been removed by another request,
	//therefore browser should act as if it had been removed by
	//its own request.
	console.log("Election does not exist or has already been removed.");
	process.exit();
}
var match = passList[eleID];
var hash = match;
if(match !== ""){
	var salt = bcrypt.getSalt(match);
	hash = bcrypt.hashSync(pass, salt);
	if(match !== hash){
		match = passList["adminpassword"];
		salt = bcrypt.getSalt(match);
		hash = bcrypt.hashSync(pass, salt);
	}
}
pass = hash;

session = spawn('python', ['../src/removeElection.py', eleID, pass, hide]);
session.stderr.on('data', function (data) {
	console.log("STDERR: "+data);
});
<commit_msg>force election ID to be toLowerCase()<commit_after>var bcrypt = require("bcryptjs");
var fs = require('fs');
var child_process = require("child_process");
var spawn = child_process.spawn;

/**
The script can be called with 2 to 4 arguments

SYNOPSIS
	node removeCustomizedElection.js -e ELECTIONID -p PASSWORD [-h]

OPTIONS:
	-e ELECTIONID: the electionID for the election, at least 7 digits of the electionID are required
	-p PASSWORD: the password to remove the election
	[-h]: if the election is hidden, this argument is required to remove it
**/

var passList = JSON.parse(fs.readFileSync("../ElectionHandler/_data_/pwd.json"));

var eleID;
var pass;
var hide = false;
for(var i = 0; i < process.argv.length; i++){
	if(process.argv[i] === '-e'){
		eleID = process.argv[i+1].slice(0,7).toLowerCase();
		i++;
	}
	else if(process.argv[i] === '-p'){
		pass = process.argv[i+1];
		i++;
	}
	else if(process.argv[i] === '-h'){
		hide = true;
	}
}

if(!passList.hasOwnProperty(eleID)){
	//means the election already has been removed by another request,
	//therefore browser should act as if it had been removed by
	//its own request.
	console.log("Election does not exist or has already been removed.");
	process.exit();
}
var match = passList[eleID];
var hash = match;
if(match !== ""){
	var salt = bcrypt.getSalt(match);
	hash = bcrypt.hashSync(pass, salt);
	if(match !== hash){
		match = passList["adminpassword"];
		salt = bcrypt.getSalt(match);
		hash = bcrypt.hashSync(pass, salt);
	}
}
pass = hash;

session = spawn('python', ['../src/removeElection.py', eleID, pass, hide]);
session.stderr.on('data', function (data) {
	console.log("STDERR: "+data);
});
<|endoftext|>


<commit_before>"use strict";

const nodePath = require("path");
const fs = require("fs");
const stripJsonComments = require("strip-json-comments");
const tagDefFromCode = require("./tag-def-from-code");
const loaders = require("./loaders");
const fsReadOptions = { encoding: "utf8" };
const extend = require("raptor-util/extend");
const types = require("./types");

const tagFileTypes = [
  "template",
  "renderer",
  "transformer",
  "code-generator",
  "node-factory"
];

const searchFiles = [
  { name: "index.marko", type: "template" },
  { name: "renderer", type: "renderer" },
  { name: "index", type: "renderer" },
  { name: "template.marko", type: "template" },
  { name: "template.html", type: "template" },
  { name: "code-generator", type: "code-generator" },
  { name: "node-factory", type: "node-factory" },
  { name: "transformer", type: "transformer" }
];

function createDefaultTagDef() {
  return {
    attributes: {
      "*": {
        type: "string",
        targetProperty: null,
        preserveName: false
      }
    }
  };
}

function getFileMap(dirname) {
  let fileMap = {};
  let files = fs.readdirSync(dirname);

  files.forEach(file => {
    let extName = nodePath.extname(file);
    let baseName = file.slice(0, -1 * extName.length);
    let fullPath = nodePath.join(dirname, file);
    fileMap[baseName] = fileMap[baseName] || {};
    fileMap[baseName][extName] = fullPath;
    fileMap[file] = fileMap[file] || {};
    fileMap[file].__path = fullPath;
  });

  return fileMap;
}

function getPath(filename, fileMap) {
  let file = fileMap[filename];

  if (!file) return;
  if (file.__path) return file.__path;
  if (file.js) return file[".js"];

  return file[Object.keys(file)[0]];
}

function findAndSetFile(tagDef, tagDirname) {
  if (!fs.statSync(tagDirname).isDirectory()) {
    return;
  }

  let tagName = nodePath.basename(tagDirname);
  let fileMap = getFileMap(tagDirname);

  for (let i = 0; i < searchFiles.length; i++) {
    let name = searchFiles[i].name;
    let type = searchFiles[i].type;
    let repeatedName = tagName + "." + name.replace("index.", "");
    let path = getPath(name, fileMap) || getPath(repeatedName, fileMap);

    if (path) {
      tagDef[type] = path;
      return true;
    }
  }
}

function hasFile(tagDef) {
  for (let i = 0; i < tagFileTypes.length; i++) {
    if (tagDef[tagFileTypes[i]]) return true;
  }
  return false;
}

/**
 * @param {String} tagsConfigPath path to tag definition file
 * @param {String} tagsConfigDirname path to directory of tags config file (should be path.dirname(tagsConfigPath))
 * @param {String|Object} dir the path to directory to scan
 * @param {String} taglib the taglib that is being loaded
 */
module.exports = function scanTagsDir(
  tagsConfigPath,
  tagsConfigDirname,
  dir,
  taglib,
  dependencyChain
) {
  let prefix;

  if (typeof dir === "object") {
    prefix = dir.prefix;
    dir = dir.path;
  }

  if (prefix == null) {
    // no prefix by default
    prefix = "";
  }

  dir = nodePath.resolve(tagsConfigDirname, dir);
  let children = fs.readdirSync(dir);

  for (let i = 0, len = children.length; i < len; i++) {
    let childFilename = children[i];
    if (childFilename === "node_modules") {
      continue;
    }

    let tagName;
    let tagDef = null;
    let tagDirname;
    let tagJsonPath;

    let ext = nodePath.extname(childFilename);
    if (ext === ".marko") {
      tagName = childFilename.slice(0, 0 - ext.length);
      tagDirname = dir;
      tagDef = createDefaultTagDef();
      tagDef.template = nodePath.join(dir, childFilename);
    } else {
      tagName = prefix + childFilename;

      tagDirname = nodePath.join(dir, childFilename);
      tagJsonPath = nodePath.join(tagDirname, "marko-tag.json");

      let hasTagJson = false;
      if (fs.existsSync(tagJsonPath)) {
        hasTagJson = true;
        // marko-tag.json exists in the directory, use that as the tag definition
        try {
          tagDef = JSON.parse(
            stripJsonComments(fs.readFileSync(tagJsonPath, fsReadOptions))
          );
        } catch (e) {
          throw new Error(
            'Unable to parse JSON file at path "' +
              tagJsonPath +
              '". Error: ' +
              e
          );
        }
      } else {
        tagJsonPath = null;
        tagDef = createDefaultTagDef();
      }

      if (!hasFile(tagDef)) {
        let fileWasSet = findAndSetFile(tagDef, tagDirname);
        if (!fileWasSet) {
          if (hasTagJson) {
            throw new Error(
              "Invalid tag file: " +
                tagJsonPath +
                ". Neither a renderer or a template was found for tag. " +
                JSON.stringify(tagDef, null, 2)
            );
          } else {
            // Skip this directory... there doesn't appear to be anything in it
            continue;
          }
        }
      }

      if (!hasTagJson && (tagDef.renderer || tagDef.template)) {
        let templateCode = fs.readFileSync(
          tagDef.renderer || tagDef.template,
          fsReadOptions
        );
        let extractedTagDef = tagDefFromCode.extractTagDef(templateCode);
        if (extractedTagDef) {
          extend(tagDef, extractedTagDef);
        }
      }
    }

    let tagDependencyChain;

    if (tagJsonPath) {
      tagDependencyChain = dependencyChain.append(tagJsonPath);
    } else {
      tagDependencyChain = dependencyChain.append(tagDirname);
    }

    let tag = new types.Tag(tagJsonPath || tagDirname);
    loaders.loadTagFromProps(tag, tagDef, tagDependencyChain);
    tag.name = tag.name || tagName;
    taglib.addTag(tag);
  }
};
<commit_msg>fix: prevent potential race condition while tag scanning<commit_after>"use strict";

const nodePath = require("path");
const fs = require("fs");
const stripJsonComments = require("strip-json-comments");
const tagDefFromCode = require("./tag-def-from-code");
const loaders = require("./loaders");
const fsReadOptions = { encoding: "utf8" };
const extend = require("raptor-util/extend");
const types = require("./types");

const tagFileTypes = [
  "template",
  "renderer",
  "transformer",
  "code-generator",
  "node-factory"
];

const searchFiles = [
  { name: "index.marko", type: "template" },
  { name: "renderer", type: "renderer" },
  { name: "index", type: "renderer" },
  { name: "template.marko", type: "template" },
  { name: "template.html", type: "template" },
  { name: "code-generator", type: "code-generator" },
  { name: "node-factory", type: "node-factory" },
  { name: "transformer", type: "transformer" }
];

function createDefaultTagDef() {
  return {
    attributes: {
      "*": {
        type: "string",
        targetProperty: null,
        preserveName: false
      }
    }
  };
}

function getFileMap(dirname) {
  let fileMap = {};
  let files = fs.readdirSync(dirname);

  files.forEach(file => {
    let extName = nodePath.extname(file);
    let baseName = file.slice(0, -1 * extName.length);
    let fullPath = nodePath.join(dirname, file);
    fileMap[baseName] = fileMap[baseName] || {};
    fileMap[baseName][extName] = fullPath;
    fileMap[file] = fileMap[file] || {};
    fileMap[file].__path = fullPath;
  });

  return fileMap;
}

function getPath(filename, fileMap) {
  let file = fileMap[filename];

  if (!file) return;
  if (file.__path) return file.__path;
  if (file.js) return file[".js"];

  return file[Object.keys(file)[0]];
}

function findAndSetFile(tagDef, tagDirname) {
  try {
    if (!fs.statSync(tagDirname).isDirectory()) {
      return;
    }
  } catch (_) {
    return;
  }

  let tagName = nodePath.basename(tagDirname);
  let fileMap = getFileMap(tagDirname);

  for (let i = 0; i < searchFiles.length; i++) {
    let name = searchFiles[i].name;
    let type = searchFiles[i].type;
    let repeatedName = tagName + "." + name.replace("index.", "");
    let path = getPath(name, fileMap) || getPath(repeatedName, fileMap);

    if (path) {
      tagDef[type] = path;
      return true;
    }
  }
}

function hasFile(tagDef) {
  for (let i = 0; i < tagFileTypes.length; i++) {
    if (tagDef[tagFileTypes[i]]) return true;
  }
  return false;
}

/**
 * @param {String} tagsConfigPath path to tag definition file
 * @param {String} tagsConfigDirname path to directory of tags config file (should be path.dirname(tagsConfigPath))
 * @param {String|Object} dir the path to directory to scan
 * @param {String} taglib the taglib that is being loaded
 */
module.exports = function scanTagsDir(
  tagsConfigPath,
  tagsConfigDirname,
  dir,
  taglib,
  dependencyChain
) {
  let prefix;

  if (typeof dir === "object") {
    prefix = dir.prefix;
    dir = dir.path;
  }

  if (prefix == null) {
    // no prefix by default
    prefix = "";
  }

  dir = nodePath.resolve(tagsConfigDirname, dir);
  let children = fs.readdirSync(dir);

  for (let i = 0, len = children.length; i < len; i++) {
    let childFilename = children[i];
    if (childFilename === "node_modules") {
      continue;
    }

    let tagName;
    let tagDef = null;
    let tagDirname;
    let tagJsonPath;

    let ext = nodePath.extname(childFilename);
    if (ext === ".marko") {
      tagName = childFilename.slice(0, 0 - ext.length);
      tagDirname = dir;
      tagDef = createDefaultTagDef();
      tagDef.template = nodePath.join(dir, childFilename);
    } else {
      tagName = prefix + childFilename;

      tagDirname = nodePath.join(dir, childFilename);
      tagJsonPath = nodePath.join(tagDirname, "marko-tag.json");

      let hasTagJson = false;
      if (fs.existsSync(tagJsonPath)) {
        hasTagJson = true;
        // marko-tag.json exists in the directory, use that as the tag definition
        try {
          tagDef = JSON.parse(
            stripJsonComments(fs.readFileSync(tagJsonPath, fsReadOptions))
          );
        } catch (e) {
          throw new Error(
            'Unable to parse JSON file at path "' +
              tagJsonPath +
              '". Error: ' +
              e
          );
        }
      } else {
        tagJsonPath = null;
        tagDef = createDefaultTagDef();
      }

      if (!hasFile(tagDef)) {
        let fileWasSet = findAndSetFile(tagDef, tagDirname);
        if (!fileWasSet) {
          if (hasTagJson) {
            throw new Error(
              "Invalid tag file: " +
                tagJsonPath +
                ". Neither a renderer or a template was found for tag. " +
                JSON.stringify(tagDef, null, 2)
            );
          } else {
            // Skip this directory... there doesn't appear to be anything in it
            continue;
          }
        }
      }

      if (!hasTagJson && (tagDef.renderer || tagDef.template)) {
        let templateCode = fs.readFileSync(
          tagDef.renderer || tagDef.template,
          fsReadOptions
        );
        let extractedTagDef = tagDefFromCode.extractTagDef(templateCode);
        if (extractedTagDef) {
          extend(tagDef, extractedTagDef);
        }
      }
    }

    let tagDependencyChain;

    if (tagJsonPath) {
      tagDependencyChain = dependencyChain.append(tagJsonPath);
    } else {
      tagDependencyChain = dependencyChain.append(tagDirname);
    }

    let tag = new types.Tag(tagJsonPath || tagDirname);
    loaders.loadTagFromProps(tag, tagDef, tagDependencyChain);
    tag.name = tag.name || tagName;
    taglib.addTag(tag);
  }
};
<|endoftext|>


<commit_before>/**
 * @fileoverview Disallow unused properties, data or computed properties.
 */

'use strict';

const remove = require('lodash/remove');
const utils = require('eslint-plugin-vue/lib/utils');

const getReferencesNames = references => {
  if (!references || !references.length) {
    return [];
  }

  return references.map(reference => {
    if (!reference.id || !reference.id.name) {
      return;
    }

    return reference.id.name;
  });
};

const reportUnusedProperties = (context, properties) => {
  if (!properties || !properties.length) {
    return;
  }

  properties.forEach(property => {
    let kind = 'property';
    if (property.groupName === 'data') {
      kind = 'data';
    } else if (property.groupName === 'computed') {
      kind = 'computed property';
    }

    context.report({
      node: property.node,
      message: `Unused ${kind} found: "${property.name}"`,
    });
  });
};

const create = context => {
  let hasTemplate;
  let rootTemplateEnd;
  let unusedProperties = [];
  let thisExpressionsVariablesNames = [];

  const initialize = {
    Program(node) {
      if (context.parserServices.getTemplateBodyTokenStore == null) {
        context.report({
          loc: { line: 1, column: 0 },
          message:
            'Use the latest vue-eslint-parser. See also https://vuejs.github.io/eslint-plugin-vue/user-guide/#what-is-the-use-the-latest-vue-eslint-parser-error.',
        });
        return;
      }

      hasTemplate = Boolean(node.templateBody);
    },
  };

  const scriptVisitor = Object.assign(
    {},
    {
      'MemberExpression[object.type="ThisExpression"][property.type="Identifier"][property.name]'(
        node
      ) {
        thisExpressionsVariablesNames.push(node.property.name);
      },
    },
    utils.executeOnVue(context, obj => {
      unusedProperties = Array.from(
        utils.iterateProperties(obj, new Set(['props', 'data', 'computed']))
      );

      const watchers = Array.from(utils.iterateProperties(obj, new Set(['watch'])));
      const watchersNames = watchers.map(watcher => watcher.name);

      remove(unusedProperties, property => {
        return (
          thisExpressionsVariablesNames.includes(property.name) ||
          watchersNames.includes(property.name)
        );
      });

      if (!hasTemplate && unusedProperties.length) {
        reportUnusedProperties(context, unusedProperties);
      }
    })
  );

  const templateVisitor = {
    'VExpressionContainer[expression!=null][references]'(node) {
      const referencesNames = getReferencesNames(node.references);

      remove(unusedProperties, property => {
        return referencesNames.includes(property.name);
      });
    },
    // save root template end location - just a helper to be used
    // for a decision if a parser reached the end of the root template
    "VElement[name='template']"(node) {
      if (rootTemplateEnd) {
        return;
      }

      rootTemplateEnd = node.loc.end;
    },
    "VElement[name='template']:exit"(node) {
      if (node.loc.end !== rootTemplateEnd) {
        return;
      }

      if (unusedProperties.length) {
        reportUnusedProperties(context, unusedProperties);
      }
    },
  };

  return Object.assign(
    {},
    initialize,
    utils.defineTemplateBodyVisitor(context, templateVisitor, scriptVisitor)
  );
};

module.exports = {
  meta: {
    docs: {
      description: 'Disallow unused properties, data or computed properties',
    },
    fixable: null,
  },
  create,
};
<commit_msg>Define constants for properties groups and their labels<commit_after>/**
 * @fileoverview Disallow unused properties, data or computed properties.
 */

'use strict';

const remove = require('lodash/remove');
const utils = require('eslint-plugin-vue/lib/utils');

const GROUP_PROPERTY = 'props';
const GROUP_DATA = 'data';
const GROUP_COMPUTED_PROPERTY = 'computed';
const GROUP_WATCHER = 'watch';

const PROPERTY_LABEL = {
  [GROUP_PROPERTY]: 'property',
  [GROUP_DATA]: 'data',
  [GROUP_COMPUTED_PROPERTY]: 'computed property',
};

const getReferencesNames = references => {
  if (!references || !references.length) {
    return [];
  }

  return references.map(reference => {
    if (!reference.id || !reference.id.name) {
      return;
    }

    return reference.id.name;
  });
};

const reportUnusedProperties = (context, properties) => {
  if (!properties || !properties.length) {
    return;
  }

  properties.forEach(property => {
    context.report({
      node: property.node,
      message: `Unused ${PROPERTY_LABEL[property.groupName]} found: "${property.name}"`,
    });
  });
};

const create = context => {
  let hasTemplate;
  let rootTemplateEnd;
  let unusedProperties = [];
  let thisExpressionsVariablesNames = [];

  const initialize = {
    Program(node) {
      if (context.parserServices.getTemplateBodyTokenStore == null) {
        context.report({
          loc: { line: 1, column: 0 },
          message:
            'Use the latest vue-eslint-parser. See also https://vuejs.github.io/eslint-plugin-vue/user-guide/#what-is-the-use-the-latest-vue-eslint-parser-error.',
        });
        return;
      }

      hasTemplate = Boolean(node.templateBody);
    },
  };

  const scriptVisitor = Object.assign(
    {},
    {
      'MemberExpression[object.type="ThisExpression"][property.type="Identifier"][property.name]'(
        node
      ) {
        thisExpressionsVariablesNames.push(node.property.name);
      },
    },
    utils.executeOnVue(context, obj => {
      unusedProperties = Array.from(
        utils.iterateProperties(obj, new Set([GROUP_PROPERTY, GROUP_DATA, GROUP_COMPUTED_PROPERTY]))
      );

      const watchers = Array.from(utils.iterateProperties(obj, new Set([GROUP_WATCHER])));
      const watchersNames = watchers.map(watcher => watcher.name);

      remove(unusedProperties, property => {
        return (
          thisExpressionsVariablesNames.includes(property.name) ||
          watchersNames.includes(property.name)
        );
      });

      if (!hasTemplate && unusedProperties.length) {
        reportUnusedProperties(context, unusedProperties);
      }
    })
  );

  const templateVisitor = {
    'VExpressionContainer[expression!=null][references]'(node) {
      const referencesNames = getReferencesNames(node.references);

      remove(unusedProperties, property => {
        return referencesNames.includes(property.name);
      });
    },
    // save root template end location - just a helper to be used
    // for a decision if a parser reached the end of the root template
    "VElement[name='template']"(node) {
      if (rootTemplateEnd) {
        return;
      }

      rootTemplateEnd = node.loc.end;
    },
    "VElement[name='template']:exit"(node) {
      if (node.loc.end !== rootTemplateEnd) {
        return;
      }

      if (unusedProperties.length) {
        reportUnusedProperties(context, unusedProperties);
      }
    },
  };

  return Object.assign(
    {},
    initialize,
    utils.defineTemplateBodyVisitor(context, templateVisitor, scriptVisitor)
  );
};

module.exports = {
  meta: {
    docs: {
      description: 'Disallow unused properties, data or computed properties',
    },
    fixable: null,
  },
  create,
};
<|endoftext|>


<commit_before>// @flow

import React from 'react'
import { AppRegistry } from 'react-native'

import { StackNavigator, TabNavigator } from 'react-navigation'
import SRStudyList from './SRStudyList'
import SRStudyTaskEditor from './SRStudyTaskEditor'
import SRSettings from './SRSettings'

import { reducer } from './dataModel/SRSimpleDataModel'
import { createStore } from 'redux'
import PropTypes from 'prop-types'
import { tintColor } from './SRSettings'

const SettingsStackNavigator = StackNavigator({
  Settings: { screen: SRSettings },
  },{
  mode: 'modal',
  }
)

const SpaceReminder = StackNavigator({
  StudyList: { screen: SRStudyList },
  SRStudyTaskEditor: { screen: SRStudyTaskEditor},
  }
)

class Provider extends React.Component {
  getChildContext() {
    return {
      store: this.props.store
    }
  }
  render() {
    return this.props.children
  }
}

Provider.childContextTypes = {
  store: PropTypes.object
}

class TaylorSwift extends React.Component {
  render() {
    const { store } = this.context

    const screenProps = {
      store: store,
    }

    return (
      <SpaceReminder screenProps={screenProps}/>
    )
  }
}

TaylorSwift.contextTypes = {
  store: PropTypes.object
}

export default class App extends React.Component {
  render() {
    return (
      <Provider store={createStore(reducer)}>
        <TaylorSwift />
      </Provider>
    )
  }
}

AppRegistry.registerComponent('SpaceReminder', () => App)
<commit_msg>Added persistent storage using Redux Persist.<commit_after>// @flow

import React from 'react'
import { AppRegistry, AsyncStorage } from 'react-native'
import PropTypes from 'prop-types'
import { StackNavigator, TabNavigator } from 'react-navigation'
import { createStore } from 'redux'
import { persistStore, autoRehydrate } from 'redux-persist'

import SRStudyList from './SRStudyList'
import SRStudyTaskEditor from './SRStudyTaskEditor'
import SRSettings from './SRSettings'
import { reducer } from './dataModel/SRSimpleDataModel'

const store = createStore(reducer, undefined, autoRehydrate())
persistStore(store, {storage: AsyncStorage})

const SettingsStackNavigator = StackNavigator({
  Settings: { screen: SRSettings },
  },{
  mode: 'modal',
  }
)

const SpaceReminder = StackNavigator({
  StudyList: { screen: SRStudyList },
  SRStudyTaskEditor: { screen: SRStudyTaskEditor},
  }
)

class Provider extends React.Component {
  getChildContext() {
    return {
      store: this.props.store
    }
  }
  render() {
    return this.props.children
  }
}

Provider.childContextTypes = {
  store: PropTypes.object
}

class TaylorSwift extends React.Component {
  render() {
    const { store } = this.context

    const screenProps = {
      store: store,
    }

    return (
      <SpaceReminder screenProps={screenProps}/>
    )
  }
}

TaylorSwift.contextTypes = {
  store: PropTypes.object
}

export default class App extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <TaylorSwift />
      </Provider>
    )
  }
}

AppRegistry.registerComponent('SpaceReminder', () => App)
<|endoftext|>


<commit_before>import { Router as router } from 'express';
import * as doorRepository from '../repositories/door';
import * as doorService from '../services/door';
import { ensureAuthenticated } from '../lib/auth';

const routes = router();

routes.get('/', (req, res) => {
  doorRepository.loadDoors().then(doors => {
    doors.map(door => {
      door.status = doorService.getStatus(door);
    });
    return res.send(doors);
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

routes.get('/:doorId/status', (req, res) => {
  doorRepository.loadDoorById(req.params.doorId).then(door => {
    return res.send(doorService.getStatus(door));
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

routes.post('/:doorId/toggle', ensureAuthenticated, (req, res) => {
  doorRepository.loadDoorById(req.params.doorId).then(door => {
    return res.send(doorService.toggle(door));
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

routes.get('/:doorId/open', (req, res) => {
  doorRepository.loadDoorById(req.params.doorId).then(door => {
    return res.send(doorService.open(door));
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

routes.get('/:doorId/close', (req, res) => {
  doorRepository.loadDoorById(req.params.doorId).then(door => {
    return res.send(doorService.close(door));
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

export default routes;
<commit_msg>Add authentication to endpoint actions<commit_after>import { Router as router } from 'express';
import * as doorRepository from '../repositories/door';
import * as doorService from '../services/door';
import { ensureAuthenticated } from '../lib/auth';

const routes = router();

routes.get('/', (req, res) => {
  doorRepository.loadDoors().then(doors => {
    doors.map(door => {
      door.status = doorService.getStatus(door);
    });
    return res.send(doors);
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

routes.get('/:doorId/status', (req, res) => {
  doorRepository.loadDoorById(req.params.doorId).then(door => {
    return res.send(doorService.getStatus(door));
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

routes.post('/:doorId/toggle', ensureAuthenticated, (req, res) => {
  doorRepository.loadDoorById(req.params.doorId).then(door => {
    return res.send(doorService.toggle(door));
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

routes.post('/:doorId/open', ensureAuthenticated, (req, res) => {
  doorRepository.loadDoorById(req.params.doorId).then(door => {
    return res.send(doorService.open(door));
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

routes.post('/:doorId/close', ensureAuthenticated, (req, res) => {
  doorRepository.loadDoorById(req.params.doorId).then(door => {
    return res.send(doorService.close(door));
  }).catch(err => {
    res.status(500).send(err.message);
  });
});

export default routes;
<|endoftext|>


<commit_before>import * as React from "react";
import * as moment from "moment-timezone";

import TZChooser from "./tz-chooser";
import tz from "./tz";

class Clock {
  getInitialState() {
    return {tz: tz(), t: moment(), format: "YYYY-DD-MM hh:mm:ss"};
  }
  handleTZChange(tzNew) {
    this.setState({tz: tzNew})
  }
  tick() {
    var now = new Date(),
        millis = now.getTime() % 1000,
        justAfterTheNextSecond = 2 + (1000 - millis);
    if (this.timer) clearTimeout(this.timer);
    this.timer = setInterval(() => {
      this.setState({t: moment()});
      this.tick();
    }, justAfterTheNextSecond);
  }
  render() {
    this.tick();
    var t = this.state.t.tz(this.state.tz).format(this.state.format);
    return

             {t}
             <TZChooser onChange={this.handleTZChange} />

  }
}

export default React.createClass(Clock.prototype);
<commit_msg>24 hour time.<commit_after>import * as React from "react";
import * as moment from "moment-timezone";

import TZChooser from "./tz-chooser";
import tz from "./tz";

class Clock {
  getInitialState() {
    return {tz: tz(), t: moment(), format: "YYYY-DD-MM HH:mm:ss"};
  }
  handleTZChange(tzNew) {
    this.setState({tz: tzNew})
  }
  tick() {
    var now = new Date(),
        millis = now.getTime() % 1000,
        justAfterTheNextSecond = 2 + (1000 - millis);
    if (this.timer) clearTimeout(this.timer);
    this.timer = setInterval(() => {
      this.setState({t: moment()});
      this.tick();
    }, justAfterTheNextSecond);
  }
  render() {
    this.tick();
    var t = this.state.t.tz(this.state.tz).format(this.state.format);
    return

             {t}
             <TZChooser onChange={this.handleTZChange} />

  }
}

export default React.createClass(Clock.prototype);
<|endoftext|>


<commit_before>var mongoSetup = require('./../index.js');
var cp = mongoSetup.collectionPromises;

var connectionData = {
    connectionString : "mongodb://localhost:27017/create_index"
};

mongoSetup.connectTo(connectionData)
    .then(cp.useCollection("MyCollection"))
    .then(cp.createIndex())
    .then(cp.createIndex({name : 1}, {name : "name_index"}))
    .catch(mongoSetup.handleError());<commit_msg>Fixed the create index example<commit_after>var mongoSetup = require('./../index.js');
var cp = mongoSetup.collectionPromises;

var connectionData = {
    connectionString : "mongodb://localhost:27017/create_index"
};

mongoSetup.connectTo(connectionData)
    .then(cp.useCollection("MyCollection"))
    .then(cp.createIndex({name : 1}, {name : "name_index"}))
    .then(cp.disconnect())
    .catch(mongoSetup.handleError());<|endoftext|>