<commit_before>import _ from 'lodash';
import { osmEntity } from './entity';
import { geoExtent } from '../geo/index';

export function osmNode() {
    if (!(this instanceof osmNode)) {
        return (new osmNode()).initialize(arguments);
    } else if (arguments.length) {
        this.initialize(arguments);
    }
}

osmEntity.node = osmNode;

osmNode.prototype = Object.create(osmEntity.prototype);

_.extend(osmNode.prototype, {

    type: 'node',

    extent: function() {
        return new geoExtent(this.loc);
    },

    geometry: function(graph) {
        return graph.transient(this, 'geometry', function() {
            return graph.isPoi(this) ? 'point' : 'vertex';
        });
    },

    move: function(loc) {
        return this.update({loc: loc});
    },

    isDegenerate: function() {
        return !(
            Array.isArray(this.loc) && this.loc.length === 2 &&
            this.loc[0] >= -180 && this.loc[0] <= 180 &&
            this.loc[1] >= -90 && this.loc[1] <= 90
        );
    },

    isEndpoint: function(resolver) {
        return resolver.transient(this, 'isEndpoint', function() {
            var id = this.id;
            return resolver.parentWays(this).filter(function(parent) {
                return !parent.isClosed() && !!parent.affix(id);
            }).length > 0;
        });
    },

    isConnected: function(resolver) {
        return resolver.transient(this, 'isConnected', function() {
            var parents = resolver.parentWays(this);

            // vertex is connected to multiple parent ways
            if (parents.length > 1) {
                return true;

            } else if (parents.length === 1) {
                var way = parents[0],
                    nodes = way.nodes.slice();
                if (way.isClosed()) { nodes.pop(); }  // ignore connecting node if closed

                // return true if vertex appears multiple times (way is self intersecting)
                return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
            }

            return false;
        });
    },

    isIntersection: function(resolver) {
        return resolver.transient(this, 'isIntersection', function() {
            return resolver.parentWays(this).filter(function(parent) {
                return (parent.tags.highway ||
                    parent.tags.waterway ||
                    parent.tags.railway ||
                    parent.tags.aeroway) &&
                    parent.geometry(resolver) === 'line';
            }).length > 1;
        });
    },

    isHighwayIntersection: function(resolver) {
        return resolver.transient(this, 'isHighwayIntersection', function() {
            return resolver.parentWays(this).filter(function(parent) {
                return parent.tags.highway && parent.geometry(resolver) === 'line';
            }).length > 1;
        });
    },

    isOnAddressLine: function(resolver) {
        return resolver.transient(this, 'isOnAddressLine', function() {
            return resolver.parentWays(this).filter(function(parent) {
                return parent.tags.hasOwnProperty('addr:interpolation') &&
                    parent.geometry(resolver) === 'line';
            }).length > 0;
        });
    },

    asJXON: function(changeset_id) {
        var r = {
            node: {
                '@id': this.osmId(),
                '@lon': this.loc[0],
                '@lat': this.loc[1],
                '@version': (this.version || 0),
                tag: _.map(this.tags, function(v, k) {
                    return { keyAttributes: { k: k, v: v } };
                })
            }
        };
        if (changeset_id) r.node['@changeset'] = changeset_id;
        return r;
    },

    asGeoJSON: function() {
        return {
            type: 'Point',
            coordinates: this.loc
        };
    }
});
<commit_msg>Only show connected vertex if it connects an interesting line<commit_after>import _ from 'lodash';
import { osmEntity } from './entity';
import { geoExtent } from '../geo/index';

export function osmNode() {
    if (!(this instanceof osmNode)) {
        return (new osmNode()).initialize(arguments);
    } else if (arguments.length) {
        this.initialize(arguments);
    }
}

osmEntity.node = osmNode;

osmNode.prototype = Object.create(osmEntity.prototype);

_.extend(osmNode.prototype, {

    type: 'node',

    extent: function() {
        return new geoExtent(this.loc);
    },

    geometry: function(graph) {
        return graph.transient(this, 'geometry', function() {
            return graph.isPoi(this) ? 'point' : 'vertex';
        });
    },

    move: function(loc) {
        return this.update({loc: loc});
    },

    isDegenerate: function() {
        return !(
            Array.isArray(this.loc) && this.loc.length === 2 &&
            this.loc[0] >= -180 && this.loc[0] <= 180 &&
            this.loc[1] >= -90 && this.loc[1] <= 90
        );
    },

    isEndpoint: function(resolver) {
        return resolver.transient(this, 'isEndpoint', function() {
            var id = this.id;
            return resolver.parentWays(this).filter(function(parent) {
                return !parent.isClosed() && !!parent.affix(id);
            }).length > 0;
        });
    },

    isConnected: function(resolver) {
        return resolver.transient(this, 'isConnected', function() {
            var parents = resolver.parentWays(this);

            function isLine(entity) {
                return entity.geometry(resolver) === 'line' &&
                    entity.hasInterestingTags();
            }

            // vertex is connected to multiple parent lines
            if (parents.length > 1 && _.some(parents, isLine)) {
                return true;

            } else if (parents.length === 1) {
                var way = parents[0],
                    nodes = way.nodes.slice();
                if (way.isClosed()) { nodes.pop(); }  // ignore connecting node if closed

                // return true if vertex appears multiple times (way is self intersecting)
                return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
            }

            return false;
        });
    },

    isIntersection: function(resolver) {
        return resolver.transient(this, 'isIntersection', function() {
            return resolver.parentWays(this).filter(function(parent) {
                return (parent.tags.highway ||
                    parent.tags.waterway ||
                    parent.tags.railway ||
                    parent.tags.aeroway) &&
                    parent.geometry(resolver) === 'line';
            }).length > 1;
        });
    },

    isHighwayIntersection: function(resolver) {
        return resolver.transient(this, 'isHighwayIntersection', function() {
            return resolver.parentWays(this).filter(function(parent) {
                return parent.tags.highway && parent.geometry(resolver) === 'line';
            }).length > 1;
        });
    },

    isOnAddressLine: function(resolver) {
        return resolver.transient(this, 'isOnAddressLine', function() {
            return resolver.parentWays(this).filter(function(parent) {
                return parent.tags.hasOwnProperty('addr:interpolation') &&
                    parent.geometry(resolver) === 'line';
            }).length > 0;
        });
    },

    asJXON: function(changeset_id) {
        var r = {
            node: {
                '@id': this.osmId(),
                '@lon': this.loc[0],
                '@lat': this.loc[1],
                '@version': (this.version || 0),
                tag: _.map(this.tags, function(v, k) {
                    return { keyAttributes: { k: k, v: v } };
                })
            }
        };
        if (changeset_id) r.node['@changeset'] = changeset_id;
        return r;
    },

    asGeoJSON: function() {
        return {
            type: 'Point',
            coordinates: this.loc
        };
    }
});
<|endoftext|>


<commit_before>import m from 'mithril';
import prop from 'mithril/stream';
import _ from 'underscore';
import { catarse } from '../api';
import h from '../h';
import models from '../models';
import nationalityRadio from '../c/nationality-radio';
import addressVM from '../vms/address-vm';
import addressFormInternational from './address-form-international';
import addressFormNational from './address-form-national';

const addressForm = {
    oninit: function(vnode) {
        const parsedErrors = vnode.attrs.parsedErrors;
        const statesLoader = catarse.loader(models.state.getPageOptions()),
            data = vnode.attrs.fields().address(),
            vm = addressVM({
                data,
            }),
            defaultCountryID = vm.defaultCountryID,
            defaultForeignCountryID = vm.defaultForeignCountryID,
            states = prop([]),
            zipCodeErrorMessage = prop(''),
            fields = vm.fields || vnode.attrs.addressFields,
            errors = {
                countryID: prop(parsedErrors ? parsedErrors.hasError('country_id') : false),
                stateID: prop(parsedErrors ? parsedErrors.hasError('state') : false),
                addressStreet: prop(parsedErrors ? parsedErrors.hasError('street') : false),
                addressNumber: prop(parsedErrors ? parsedErrors.hasError('number') : false),
                addressComplement: prop(false),
                addressNeighbourhood: prop(parsedErrors ? parsedErrors.hasError('neighbourhood') : false),
                addressCity: prop(parsedErrors ? parsedErrors.hasError('city') : false),
                addressState: prop(parsedErrors ? parsedErrors.hasError('state') : false),
                addressZipCode: prop(parsedErrors ? parsedErrors.hasError('zipcode') : false),
                phoneNumber: prop(parsedErrors ? parsedErrors.hasError('phonenumber') : false),
            },
            phoneMask = _.partial(h.mask, '(99) 9999-99999'),
            zipcodeMask = _.partial(h.mask, '99999-999'),
            applyZipcodeMask = _.compose(
                fields.addressZipCode,
                zipcodeMask
            ),
            applyPhoneMask = _.compose(
                fields.phoneNumber,
                phoneMask
            ),
            international = vnode.attrs.disableInternational ? prop(false) : vnode.attrs.international || vm.international;

        const checkPhone = () => {
            let hasError = false;
            const phone = fields.phoneNumber(),
                strippedPhone = String(phone || '').replace(/[\(|\)|\-|\s]*/g, '');

            if (strippedPhone.length < 10) {
                errors.phoneNumber(true);
                hasError = true;
            } else {
                const controlDigit = Number(strippedPhone.charAt(2));
                if (!(controlDigit >= 2 && controlDigit <= 9)) {
                    errors.phoneNumber(true);
                    hasError = true;
                }
            }
            return hasError;
        };

        _.extend(vnode.attrs.fields(), {
            validate: () => {
                let hasError = false;
                const fieldsToIgnore = international()
                    ? ['id', 'stateID', 'addressComplement', 'addressNumber', 'addressNeighbourhood', 'phoneNumber']
                    : ['id', 'addressComplement', 'addressState', 'phoneNumber'];
                // clear all errors
                _.mapObject(errors, (val, key) => {
                    val(false);
                });
                // check for empty fields
                _.mapObject(_.omit(fields, fieldsToIgnore), (val, key) => {
                    if (!val()) {
                        errors[key](true);
                        hasError = true;
                    }
                });
                if (!international()) {
                    const hasPhoneError = checkPhone();
                    hasError = hasError || hasPhoneError;
                }
                return !hasError;
            },
        });

        const lookupZipCode = zipCode => {
            fields.addressZipCode(zipCode);
            if (zipCode.length === 9) {
                m.request({
                    method: 'GET',
                    url: `https://api.pagar.me/1/zipcodes/${zipCode}`,
                })
                    .then(response => {
                        fields.addressStreet(response.street);
                        fields.addressNeighbourhood(response.neighborhood);
                        fields.addressCity(response.city);
                        fields.stateID(_.find(states(), state => state.acronym === response.state).id);
                        errors.addressStreet(false);
                        errors.addressNeighbourhood(false);
                        errors.addressCity(false);
                        errors.stateID(false);
                        errors.addressZipCode(false);
                    })
                    .catch(err => {
                        zipCodeErrorMessage(err.errors[0].message);
                        errors.addressZipCode(true);
                    });
            }
        };

        statesLoader.load().then(data => {
            states(data);
            addressVM.states(states());
        });
        vnode.state = {
            lookupZipCode,
            zipCodeErrorMessage,
            errors,
            applyPhoneMask,
            applyZipcodeMask,
            defaultCountryID,
            defaultForeignCountryID,
            fields,
            international,
            states,
            parsedErrors
        };
    },
    view: function({ state, attrs }) {

        if (state.parsedErrors) {
            const parsedErrors = state.parsedErrors;
            state.errors = {
                countryID: prop(parsedErrors ? parsedErrors.hasError('country_id') : false),
                stateID: prop(parsedErrors ? parsedErrors.hasError('state') : false),
                addressStreet: prop(parsedErrors ? parsedErrors.hasError('street') : false),
                addressNumber: prop(parsedErrors ? parsedErrors.hasError('number') : false),
                addressComplement: prop(false),
                addressNeighbourhood: prop(parsedErrors ? parsedErrors.hasError('neighbourhood') : false),
                addressCity: prop(parsedErrors ? parsedErrors.hasError('city') : false),
                addressState: prop(parsedErrors ? parsedErrors.hasError('state') : false),
                addressZipCode: prop(parsedErrors ? parsedErrors.hasError('zipcode') : false),
                phoneNumber: prop(parsedErrors ? parsedErrors.hasError('phonenumber') : false),
            };
        }

        const fields = state.fields,
            international = state.international,
            defaultCountryID = state.defaultCountryID,
            defaultForeignCountryID = state.defaultForeignCountryID,
            countryName = attrs.countryName,
            errors = state.errors,
            // hash to send to rails
            address = {
                id: fields.id(),
                country_id: fields.countryID(),
                state_id: fields.stateID(),
                address_street: fields.addressStreet(),
                address_number: fields.addressNumber(),
                address_complement: fields.addressComplement(),
                address_neighbourhood: fields.addressNeighbourhood(),
                address_city: fields.addressCity(),
                address_state: fields.addressState(),
                address_zip_code: fields.addressZipCode(),
                phone_number: fields.phoneNumber(),
            },
            applyZipcodeMask = state.applyZipcodeMask,
            lookupZipCode = state.lookupZipCode,
            zipCodeErrorMessage = state.zipCodeErrorMessage,
            countryStates = state.states,
            disableInternational = attrs.disableInternational,
            hideNationality = attrs.hideNationality,
            applyPhoneMask = state.applyPhoneMask;

        attrs.fields().address(address);
        if (attrs.stateName()) {
            const stateData = _.find(state.states(), stateData => stateData.id === parseInt(fields.stateID()));
            attrs.stateName(state.states() && fields.stateID() ? stateData.name : '');
        }

        return m('#address-form.u-marginbottom-30.w-form', [
            !hideNationality
                ? m(
                      '.u-marginbottom-30',
                      m(nationalityRadio, {
                          fields,
                          defaultCountryID,
                          defaultForeignCountryID,
                          international,
                      })
                  )
                : '',
            international()
                ? m(addressFormInternational, {
                      fields,
                      disableInternational,
                      addVM: attrs.addVM,
                      international,
                      defaultCountryID,
                      defaultForeignCountryID,
                      errors,
                      applyPhoneMask,
                  })
                : m(addressFormNational, {
                      disableInternational,
                      countryName,
                      fields,
                      international,
                      defaultCountryID,
                      defaultForeignCountryID,
                      errors,
                      applyZipcodeMask,
                      lookupZipCode,
                      zipCodeErrorMessage,
                      countryStates,
                      applyPhoneMask,
                  }),
        ]);
    },
};

export default addressForm;
<commit_msg>fix where address form receives adata<commit_after>import m from 'mithril';
import prop from 'mithril/stream';
import _ from 'underscore';
import { catarse } from '../api';
import h from '../h';
import models from '../models';
import nationalityRadio from '../c/nationality-radio';
import addressVM from '../vms/address-vm';
import addressFormInternational from './address-form-international';
import addressFormNational from './address-form-national';

const addressForm = {
    oninit: function(vnode) {
        const parsedErrors = vnode.attrs.parsedErrors;
        const statesLoader = catarse.loader(models.state.getPageOptions()),
            data = vnode.attrs.fields().address(),
            vm = addressVM({
                data,
            }),
            defaultCountryID = vm.defaultCountryID,
            defaultForeignCountryID = vm.defaultForeignCountryID,
            states = prop([]),
            zipCodeErrorMessage = prop(''),
            fields = vm.fields || vnode.attrs.addressFields,
            errors = {
                countryID: prop(parsedErrors ? parsedErrors.hasError('country_id') : false),
                stateID: prop(parsedErrors ? parsedErrors.hasError('state') : false),
                addressStreet: prop(parsedErrors ? parsedErrors.hasError('street') : false),
                addressNumber: prop(parsedErrors ? parsedErrors.hasError('number') : false),
                addressComplement: prop(false),
                addressNeighbourhood: prop(parsedErrors ? parsedErrors.hasError('neighbourhood') : false),
                addressCity: prop(parsedErrors ? parsedErrors.hasError('city') : false),
                addressState: prop(parsedErrors ? parsedErrors.hasError('state') : false),
                addressZipCode: prop(parsedErrors ? parsedErrors.hasError('zipcode') : false),
                phoneNumber: prop(parsedErrors ? parsedErrors.hasError('phonenumber') : false),
            },
            phoneMask = _.partial(h.mask, '(99) 9999-99999'),
            zipcodeMask = _.partial(h.mask, '99999-999'),
            applyZipcodeMask = _.compose(
                fields.addressZipCode,
                zipcodeMask
            ),
            applyPhoneMask = _.compose(
                fields.phoneNumber,
                phoneMask
            ),
            international = vnode.attrs.disableInternational ? prop(false) : vnode.attrs.international || vm.international;

        const checkPhone = () => {
            let hasError = false;
            const phone = fields.phoneNumber(),
                strippedPhone = String(phone || '').replace(/[\(|\)|\-|\s]*/g, '');

            if (strippedPhone.length < 10) {
                errors.phoneNumber(true);
                hasError = true;
            } else {
                const controlDigit = Number(strippedPhone.charAt(2));
                if (!(controlDigit >= 2 && controlDigit <= 9)) {
                    errors.phoneNumber(true);
                    hasError = true;
                }
            }
            return hasError;
        };

        _.extend(vnode.attrs.fields(), {
            validate: () => {
                let hasError = false;
                const fieldsToIgnore = international()
                    ? ['id', 'stateID', 'addressComplement', 'addressNumber', 'addressNeighbourhood', 'phoneNumber']
                    : ['id', 'addressComplement', 'addressState', 'phoneNumber'];
                // clear all errors
                _.mapObject(errors, (val, key) => {
                    val(false);
                });
                // check for empty fields
                _.mapObject(_.omit(fields, fieldsToIgnore), (val, key) => {
                    if (!val()) {
                        errors[key](true);
                        hasError = true;
                    }
                });
                if (!international()) {
                    const hasPhoneError = checkPhone();
                    hasError = hasError || hasPhoneError;
                }
                return !hasError;
            },
        });

        const lookupZipCode = zipCode => {
            fields.addressZipCode(zipCode);
            if (zipCode.length === 9) {
                m.request({
                    method: 'GET',
                    url: `https://api.pagar.me/1/zipcodes/${zipCode}`,
                })
                    .then(response => {
                        fields.addressStreet(response.street);
                        fields.addressNeighbourhood(response.neighborhood);
                        fields.addressCity(response.city);
                        fields.stateID(_.find(states(), state => state.acronym === response.state).id);
                        errors.addressStreet(false);
                        errors.addressNeighbourhood(false);
                        errors.addressCity(false);
                        errors.stateID(false);
                        errors.addressZipCode(false);
                    })
                    .catch(err => {
                        zipCodeErrorMessage(err.errors[0].message);
                        errors.addressZipCode(true);
                    });
            }
        };

        statesLoader.load().then(data => {
            states(data);
            addressVM.states(states());
        });
        vnode.state = {
            lookupZipCode,
            zipCodeErrorMessage,
            errors,
            applyPhoneMask,
            applyZipcodeMask,
            defaultCountryID,
            defaultForeignCountryID,
            fields,
            international,
            states,
            parsedErrors
        };
    },
    view: function({ state, attrs }) {

        if (state.parsedErrors) {
            const parsedErrors = state.parsedErrors;
            state.errors = {
                countryID: prop(parsedErrors ? parsedErrors.hasError('country_id') : false),
                stateID: prop(parsedErrors ? parsedErrors.hasError('state') : false),
                addressStreet: prop(parsedErrors ? parsedErrors.hasError('street') : false),
                addressNumber: prop(parsedErrors ? parsedErrors.hasError('number') : false),
                addressComplement: prop(false),
                addressNeighbourhood: prop(parsedErrors ? parsedErrors.hasError('neighbourhood') : false),
                addressCity: prop(parsedErrors ? parsedErrors.hasError('city') : false),
                addressState: prop(parsedErrors ? parsedErrors.hasError('state') : false),
                addressZipCode: prop(parsedErrors ? parsedErrors.hasError('zipcode') : false),
                phoneNumber: prop(parsedErrors ? parsedErrors.hasError('phonenumber') : false),
            };
        }

        const fields = state.fields,
            international = state.international,
            defaultCountryID = state.defaultCountryID,
            defaultForeignCountryID = state.defaultForeignCountryID,
            countryName = attrs.countryName,
            errors = state.errors,
            // hash to send to rails
            address = {
                id: fields.id(),
                country_id: fields.countryID(),
                state_id: fields.stateID(),
                address_street: fields.addressStreet(),
                address_number: fields.addressNumber(),
                address_complement: fields.addressComplement(),
                address_neighbourhood: fields.addressNeighbourhood(),
                address_city: fields.addressCity(),
                address_state: fields.addressState(),
                address_zip_code: fields.addressZipCode(),
                phone_number: fields.phoneNumber(),
            },
            applyZipcodeMask = state.applyZipcodeMask,
            lookupZipCode = state.lookupZipCode,
            zipCodeErrorMessage = state.zipCodeErrorMessage,
            countryStates = state.states,
            disableInternational = attrs.disableInternational,
            hideNationality = attrs.hideNationality,
            applyPhoneMask = state.applyPhoneMask;

        attrs.fields().address(address);
        if (attrs.stateName && attrs.stateName()) {
            const stateData = _.find(state.states(), stateData => stateData.id === parseInt(fields.stateID()));
            attrs.stateName(state.states() && fields.stateID() ? stateData.name : '');
        }

        return m('#address-form.u-marginbottom-30.w-form', [
            !hideNationality
                ? m(
                      '.u-marginbottom-30',
                      m(nationalityRadio, {
                          fields,
                          defaultCountryID,
                          defaultForeignCountryID,
                          international,
                      })
                  )
                : '',
            international()
                ? m(addressFormInternational, {
                      fields,
                      disableInternational,
                      addVM: attrs.addVM,
                      international,
                      defaultCountryID,
                      defaultForeignCountryID,
                      errors,
                      applyPhoneMask,
                  })
                : m(addressFormNational, {
                      disableInternational,
                      countryName,
                      fields,
                      international,
                      defaultCountryID,
                      defaultForeignCountryID,
                      errors,
                      applyZipcodeMask,
                      lookupZipCode,
                      zipCodeErrorMessage,
                      countryStates,
                      applyPhoneMask,
                  }),
        ]);
    },
};

export default addressForm;
<|endoftext|>


<commit_before>var moment = require('moment')
var request = require('request')

var mock = {
	recentMeetings: [{
		attendeeOpenIds: ['o1__FsxGOvh12CjS8ZtZqcwYtZXA'],
		meetingName: '我的会议1',
		meetingRoom: '九州岛',
		from: '1460170070059',
		to: '1460170080059',
		bookerName: 'yuhao.ju'
	}],
	newMeetings: [{
		attendeeOpenIds: ['o1__FsxGOvh12CjS8ZtZqcwYtZXA'],
		meetingName: '我的会议2',
		meetingRoom: '格林威治',
		from: '1460170070059',
		to: '1460170080059',
		bookerName: 'yuhao.ju'
	}]
}

var MEETING_TYPE = {
    'NEW': 'new',
    'RECENT': 'recnet'
}

var initSchedule = function(api) {
	var schedule = require('node-schedule')

	var j = schedule.scheduleJob('*/1 * * * *', function() {
		console.log('schedule processing')
		getRemindRList(function(resData) {
			sendRemind(resData.data.recentMeetings, MEETING_TYPE.RECENT, api)
			sendRemind(resData.data.newMeetings,  MEETING_TYPE.NEW, api)
		})
	})
}

function sendRemind(meetings, type, api) {
	if(!meetings || meetings.length === 0){
		return
	}

    meetings.forEach(function(meeting) {
        var msg = ''

        if(type === MEETING_TYPE.RECENT){
            msg = '哈喽：您近期有一个会议\n'
                + '会议室：' + meeting.roomName + '\n'
                + '时间：' + getFormedDateRange(meeting.fromTime, meeting.toTime) + '\n'
                + '发起人：' + meeting.bookerId + '\n'
                + '请您准时到场 谢谢'
        } else if(type === MEETING_TYPE.NEW){
            msg = '哈喽：您有一个会议邀请\n'
                + '会议室：' + meeting.roomName + '\n'
                + '时间：' + getFormedDateRange(meeting.fromTime, meeting.toTime) + '\n'
                + '发起人：' + meeting.bookerId + '\n'
                + '如有特殊情况请联系发起人'
        }

        if (meeting.attendeeOpenIds) {
            meeting.attendeeOpenIds.forEach(function(openid) {
                // FIXME 发送消息
                api.sendText(openid, msg, function(err) {
					console.log('send' + msg);
                	if(err){
                        console.log(err);
                    }
                })
            })
        }
    })
}

function getFormedDateRange(from, to){
    var fromStr = moment(Number(from)).format("M月D日 hh:mm"),
        toStr = moment(Number(to)).format("hh:mm")

    return fromStr + '-' + toStr
}

function getRemindRList(callback) {
	request('http://115.159.119.199:8080/getMessages', function(error, response, body) {
		if (!error && response.statusCode == 200) {
			callback(JSON.parse(body))
		} else{
			callback(JSON.parse(error))
		}
	})

}

module.exports = {
	init: initSchedule
}
<commit_msg>remove bookerId<commit_after>var moment = require('moment')
var request = require('request')

var mock = {
	recentMeetings: [{
		attendeeOpenIds: ['o1__FsxGOvh12CjS8ZtZqcwYtZXA'],
		meetingName: '我的会议1',
		meetingRoom: '九州岛',
		from: '1460170070059',
		to: '1460170080059',
		bookerName: 'yuhao.ju'
	}],
	newMeetings: [{
		attendeeOpenIds: ['o1__FsxGOvh12CjS8ZtZqcwYtZXA'],
		meetingName: '我的会议2',
		meetingRoom: '格林威治',
		from: '1460170070059',
		to: '1460170080059',
		bookerName: 'yuhao.ju'
	}]
}

var MEETING_TYPE = {
    'NEW': 'new',
    'RECENT': 'recnet'
}

var initSchedule = function(api) {
	var schedule = require('node-schedule')

	var j = schedule.scheduleJob('*/1 * * * *', function() {
		console.log('schedule processing')
		getRemindRList(function(resData) {
			sendRemind(resData.data.recentMeetings, MEETING_TYPE.RECENT, api)
			sendRemind(resData.data.newMeetings,  MEETING_TYPE.NEW, api)
		})
	})
}

function sendRemind(meetings, type, api) {
	if(!meetings || meetings.length === 0){
		return
	}

    meetings.forEach(function(meeting) {
        var msg = ''

        if(type === MEETING_TYPE.RECENT){
            msg = '哈喽：您近期有一个会议\n'
                + '会议室：' + meeting.roomName + '\n'
                + '时间：' + getFormedDateRange(meeting.fromTime, meeting.toTime) + '\n'
                + '请您准时到场 谢谢'
        } else if(type === MEETING_TYPE.NEW){
            msg = '哈喽：您有一个会议邀请\n'
                + '会议室：' + meeting.roomName + '\n'
                + '时间：' + getFormedDateRange(meeting.fromTime, meeting.toTime) + '\n'
                + '如有特殊情况请联系发起人'
        }

        if (meeting.attendeeOpenIds) {
            meeting.attendeeOpenIds.forEach(function(openid) {
                // FIXME 发送消息
                api.sendText(openid, msg, function(err) {
					console.log('send' + msg);
                	if(err){
                        console.log(err);
                    }
                })
            })
        }
    })
}

function getFormedDateRange(from, to){
    var fromStr = moment(Number(from)).format("M月D日 hh:mm"),
        toStr = moment(Number(to)).format("hh:mm")

    return fromStr + '-' + toStr
}

function getRemindRList(callback) {
	request('http://115.159.119.199:8080/getMessages', function(error, response, body) {
		if (!error && response.statusCode == 200) {
			callback(JSON.parse(body))
		} else{
			callback(JSON.parse(error))
		}
	})

}

module.exports = {
	init: initSchedule
}
<|endoftext|>


<commit_before>define("dojox/data/FlickrStore", ["dojo", "dojox", "dojo/data/util/simpleFetch", "dojo/io/script", "dojo/date/stamp", "dojo/AdapterRegistry"], function(dojo, dojox) {

dojo.declare("dojox.data.FlickrStore", null, {
	constructor: function(/*Object*/args){
		//	summary:
		//		Initializer for the FlickrStore store.
		//	description:
		//		The FlickrStore is a Datastore interface to one of the basic services
		//		of the Flickr service, the public photo feed.  This does not provide
		//		access to all the services of Flickr.
		//		This store cannot do * and ? filtering as the flickr service
		//		provides no interface for wildcards.
		if(args && args.label){
			this.label = args.label;
		}
		if(args && "urlPreventCache" in args){
			this.urlPreventCache = args.urlPreventCache?true:false;
		}
	},

	_storeRef: "_S",

	label: "title",

	//Flag to allor control of if cache prevention is enabled or not.
	urlPreventCache: true,

	_assertIsItem: function(/* item */ item){
		//	summary:
		//      This function tests whether the item passed in is indeed an item in the store.
		//	item:
		//		The item to test for being contained by the store.
		if(!this.isItem(item)){
			throw new Error("dojox.data.FlickrStore: a function was passed an item argument that was not an item");
		}
	},

	_assertIsAttribute: function(/* attribute-name-string */ attribute){
		//	summary:
		//		This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
		//	attribute:
		//		The attribute to test for being contained by the store.
		if(typeof attribute !== "string"){
			throw new Error("dojox.data.FlickrStore: a function was passed an attribute argument that was not an attribute name string");
		}
	},

	getFeatures: function(){
		//	summary:
		//      See dojo.data.api.Read.getFeatures()
		return {
			'dojo.data.api.Read': true
		};
	},

	getValue: function(item, attribute, defaultValue){
		//	summary:
		//      See dojo.data.api.Read.getValue()
		var values = this.getValues(item, attribute);
		if(values && values.length > 0){
			return values[0];
		}
		return defaultValue;
	},

	getAttributes: function(item){
		//	summary:
		//      See dojo.data.api.Read.getAttributes()
		return [
			"title", "description", "author", "datePublished", "dateTaken",
			"imageUrl", "imageUrlSmall", "imageUrlMedium", "tags", "link"
		];
	},

	hasAttribute: function(item, attribute){
		//	summary:
		//      See dojo.data.api.Read.hasAttributes()
		var v = this.getValue(item,attribute);
		if(v || v === "" || v === false){
			return true;
		}
		return false;
	},

	isItemLoaded: function(item){
		 //	summary:
		 //      See dojo.data.api.Read.isItemLoaded()
		 return this.isItem(item);
	},

	loadItem: function(keywordArgs){
		//	summary:
		//      See dojo.data.api.Read.loadItem()
	},

	getLabel: function(item){
		//	summary:
		//      See dojo.data.api.Read.getLabel()
		return this.getValue(item,this.label);
	},

	getLabelAttributes: function(item){
		//	summary:
		//      See dojo.data.api.Read.getLabelAttributes()
		return [this.label];
	},

	containsValue: function(item, attribute, value){
		//	summary:
		//      See dojo.data.api.Read.containsValue()
		var values = this.getValues(item,attribute);
		for(var i = 0; i < values.length; i++){
			if(values[i] === value){
				return true;
			}
		}
		return false;
	},

	getValues: function(item, attribute){
		//	summary:
		//      See dojo.data.api.Read.getValue()

		this._assertIsItem(item);
		this._assertIsAttribute(attribute);
		var u = d.hitch(this, "_unescapeHtml");
		var s = d.hitch(d.date.stamp, "fromISOString");
		switch(attribute){
			case "title":
				return [ u(item.title) ];
			case "author":
				return [ u(item.author) ];
			case "datePublished":
				return [ s(item.published) ];
			case "dateTaken":
				return [ s(item.date_taken) ];
			case "imageUrlSmall":
				return [ item.media.m.replace(/_m\./, "_s.") ];
			case "imageUrl":
				return [ item.media.m.replace(/_m\./, ".") ];
			case "imageUrlMedium":
				return [ item.media.m ];
			case "link":
				return [ item.link ];
			case "tags":
				return item.tags.split(" ");
			case "description":
				return [ u(item.description) ];
			default:
				return [];
		}
	},

	isItem: function(item){
		//	summary:
		//      See dojo.data.api.Read.isItem()
		if(item && item[this._storeRef] === this){
			return true;
		}
		return false;
	},

	close: function(request){
		//	summary:
		//      See dojo.data.api.Read.close()
	},

	_fetchItems: function(request, fetchHandler, errorHandler){
		//	summary:
		//		Fetch flickr items that match to a query
		//	request:
		//		A request object
		//	fetchHandler:
		//		A function to call for fetched items
		//	errorHandler:
		//		A function to call on error

		var rq = request.query = request.query || {};

		//Build up the content to send the request for.
		var content = {
			format: "json",
			tagmode:"any"
		};

		d.forEach(
			[ "tags", "tagmode", "lang", "id", "ids" ],
			function(i){
				if(rq[i]){ content[i] = rq[i]; }
			}
		);

		content.id = rq.id || rq.userid || rq.groupid;

		if(rq.userids){
			content.ids = rq.userids;
		}

		//Linking this up to Flickr is a PAIN!
		var handle = null;
		var getArgs = {
			url: dojox.data.FlickrStore.urlRegistry.match(request),
			preventCache: this.urlPreventCache,
			content: content
		};
		var myHandler = d.hitch(this, function(data){
			if(!!handle){
				d.disconnect(handle);
			}

			//Process the items...
			fetchHandler(this._processFlickrData(data), request);
		});
		handle = d.connect("jsonFlickrFeed", myHandler);
		var deferred = d.io.script.get(getArgs);

		//We only set up the errback, because the callback isn't ever really used because we have
		//to link to the jsonFlickrFeed function....
		deferred.addErrback(function(error){
			d.disconnect(handle);
			errorHandler(error, request);
		});
	},

	_processFlickrData: function(data){
		 var items = [];
		 if(data.items){
			 items = data.items;
			 //Add on the store ref so that isItem can work.
			 for(var i = 0; i < data.items.length; i++){
				 var item = data.items[i];
				 item[this._storeRef] = this;
			 }
		 }
		 return items;
	},

	_unescapeHtml: function(/*String*/ str){
		// summary:
		//		Utility function to un-escape XML special characters in an
		//		HTML string.
		//	str: String.
		//		The string to un-escape
		// returns:
		//		HTML String converted back to the normal text (unescaped)
		//		characters (<,>,&, ", etc,).

		//TODO:
		//		Check to see if theres already compatible escape() in
		//		dojo.string or dojo.html
		return 	str.replace(/&/gm, "&").
					replace(/</gm, "<").
					replace(/>/gm, ">").
					replace(/"/gm, "\"").
					replace(/'/gm, "'");
	}
});

dojo.extend(dojox.data.FlickrStore, dojo.data.util.simpleFetch);

var feedsUrl = "http://api.flickr.com/services/feeds/";

var reg = dojox.data.FlickrStore.urlRegistry = new d.AdapterRegistry(true);

reg.register("group pool",
	function(request){ return !!request.query["groupid"]; },
	feedsUrl+"groups_pool.gne"
);

reg.register("default",
	function(request){ return true; },
	feedsUrl+"photos_public.gne"
);

//We have to define this because of how the Flickr API works.
//This somewhat stinks, but what can you do?
if(!jsonFlickrFeed){
	var jsonFlickrFeed = function(data){};
}

return dojox.data.FlickrStore;

});
<commit_msg>Fixed AMD-refactor-introduced error with dojo as 'd' reference. Tests pass. Refs: #12672<commit_after>define("dojox/data/FlickrStore", ["dojo", "dojox", "dojo/data/util/simpleFetch", "dojo/io/script", "dojo/date/stamp", "dojo/AdapterRegistry"], function(dojo, dojox) {

dojo.declare("dojox.data.FlickrStore", null, {
	constructor: function(/*Object*/args){
		//	summary:
		//		Initializer for the FlickrStore store.
		//	description:
		//		The FlickrStore is a Datastore interface to one of the basic services
		//		of the Flickr service, the public photo feed.  This does not provide
		//		access to all the services of Flickr.
		//		This store cannot do * and ? filtering as the flickr service
		//		provides no interface for wildcards.
		if(args && args.label){
			this.label = args.label;
		}
		if(args && "urlPreventCache" in args){
			this.urlPreventCache = args.urlPreventCache?true:false;
		}
	},

	_storeRef: "_S",

	label: "title",

	//Flag to allor control of if cache prevention is enabled or not.
	urlPreventCache: true,

	_assertIsItem: function(/* item */ item){
		//	summary:
		//      This function tests whether the item passed in is indeed an item in the store.
		//	item:
		//		The item to test for being contained by the store.
		if(!this.isItem(item)){
			throw new Error("dojox.data.FlickrStore: a function was passed an item argument that was not an item");
		}
	},

	_assertIsAttribute: function(/* attribute-name-string */ attribute){
		//	summary:
		//		This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
		//	attribute:
		//		The attribute to test for being contained by the store.
		if(typeof attribute !== "string"){
			throw new Error("dojox.data.FlickrStore: a function was passed an attribute argument that was not an attribute name string");
		}
	},

	getFeatures: function(){
		//	summary:
		//      See dojo.data.api.Read.getFeatures()
		return {
			'dojo.data.api.Read': true
		};
	},

	getValue: function(item, attribute, defaultValue){
		//	summary:
		//      See dojo.data.api.Read.getValue()
		var values = this.getValues(item, attribute);
		if(values && values.length > 0){
			return values[0];
		}
		return defaultValue;
	},

	getAttributes: function(item){
		//	summary:
		//      See dojo.data.api.Read.getAttributes()
		return [
			"title", "description", "author", "datePublished", "dateTaken",
			"imageUrl", "imageUrlSmall", "imageUrlMedium", "tags", "link"
		];
	},

	hasAttribute: function(item, attribute){
		//	summary:
		//      See dojo.data.api.Read.hasAttributes()
		var v = this.getValue(item,attribute);
		if(v || v === "" || v === false){
			return true;
		}
		return false;
	},

	isItemLoaded: function(item){
		 //	summary:
		 //      See dojo.data.api.Read.isItemLoaded()
		 return this.isItem(item);
	},

	loadItem: function(keywordArgs){
		//	summary:
		//      See dojo.data.api.Read.loadItem()
	},

	getLabel: function(item){
		//	summary:
		//      See dojo.data.api.Read.getLabel()
		return this.getValue(item,this.label);
	},

	getLabelAttributes: function(item){
		//	summary:
		//      See dojo.data.api.Read.getLabelAttributes()
		return [this.label];
	},

	containsValue: function(item, attribute, value){
		//	summary:
		//      See dojo.data.api.Read.containsValue()
		var values = this.getValues(item,attribute);
		for(var i = 0; i < values.length; i++){
			if(values[i] === value){
				return true;
			}
		}
		return false;
	},

	getValues: function(item, attribute){
		//	summary:
		//      See dojo.data.api.Read.getValue()

		this._assertIsItem(item);
		this._assertIsAttribute(attribute);
		var u = dojo.hitch(this, "_unescapeHtml");
		var s = dojo.hitch(dojo.date.stamp, "fromISOString");
		switch(attribute){
			case "title":
				return [ u(item.title) ];
			case "author":
				return [ u(item.author) ];
			case "datePublished":
				return [ s(item.published) ];
			case "dateTaken":
				return [ s(item.date_taken) ];
			case "imageUrlSmall":
				return [ item.media.m.replace(/_m\./, "_s.") ];
			case "imageUrl":
				return [ item.media.m.replace(/_m\./, ".") ];
			case "imageUrlMedium":
				return [ item.media.m ];
			case "link":
				return [ item.link ];
			case "tags":
				return item.tags.split(" ");
			case "description":
				return [ u(item.description) ];
			default:
				return [];
		}
	},

	isItem: function(item){
		//	summary:
		//      See dojo.data.api.Read.isItem()
		if(item && item[this._storeRef] === this){
			return true;
		}
		return false;
	},

	close: function(request){
		//	summary:
		//      See dojo.data.api.Read.close()
	},

	_fetchItems: function(request, fetchHandler, errorHandler){
		//	summary:
		//		Fetch flickr items that match to a query
		//	request:
		//		A request object
		//	fetchHandler:
		//		A function to call for fetched items
		//	errorHandler:
		//		A function to call on error

		var rq = request.query = request.query || {};

		//Build up the content to send the request for.
		var content = {
			format: "json",
			tagmode:"any"
		};

		dojo.forEach(
			[ "tags", "tagmode", "lang", "id", "ids" ],
			function(i){
				if(rq[i]){ content[i] = rq[i]; }
			}
		);

		content.id = rq.id || rq.userid || rq.groupid;

		if(rq.userids){
			content.ids = rq.userids;
		}

		//Linking this up to Flickr is a PAIN!
		var handle = null;
		var getArgs = {
			url: dojox.data.FlickrStore.urlRegistry.match(request),
			preventCache: this.urlPreventCache,
			content: content
		};
		var myHandler = dojo.hitch(this, function(data){
			if(!!handle){
				dojo.disconnect(handle);
			}

			//Process the items...
			fetchHandler(this._processFlickrData(data), request);
		});
		handle = dojo.connect("jsonFlickrFeed", myHandler);
		var deferred = dojo.io.script.get(getArgs);

		//We only set up the errback, because the callback isn't ever really used because we have
		//to link to the jsonFlickrFeed function....
		deferred.addErrback(function(error){
			dojo.disconnect(handle);
			errorHandler(error, request);
		});
	},

	_processFlickrData: function(data){
		 var items = [];
		 if(data.items){
			 items = data.items;
			 //Add on the store ref so that isItem can work.
			 for(var i = 0; i < data.items.length; i++){
				 var item = data.items[i];
				 item[this._storeRef] = this;
			 }
		 }
		 return items;
	},

	_unescapeHtml: function(/*String*/ str){
		// summary:
		//		Utility function to un-escape XML special characters in an
		//		HTML string.
		//	str: String.
		//		The string to un-escape
		// returns:
		//		HTML String converted back to the normal text (unescaped)
		//		characters (<,>,&, ", etc,).

		//TODO:
		//		Check to see if theres already compatible escape() in
		//		dojo.string or dojo.html
		return 	str.replace(/&/gm, "&").
					replace(/</gm, "<").
					replace(/>/gm, ">").
					replace(/"/gm, "\"").
					replace(/'/gm, "'");
	}
});

dojo.extend(dojox.data.FlickrStore, dojo.data.util.simpleFetch);

var feedsUrl = "http://api.flickr.com/services/feeds/";

var reg = dojox.data.FlickrStore.urlRegistry = new dojo.AdapterRegistry(true);

reg.register("group pool",
	function(request){ return !!request.query["groupid"]; },
	feedsUrl+"groups_pool.gne"
);

reg.register("default",
	function(request){ return true; },
	feedsUrl+"photos_public.gne"
);

//We have to define this because of how the Flickr API works.
//This somewhat stinks, but what can you do?
if(!jsonFlickrFeed){
	var jsonFlickrFeed = function(data){};
}

return dojox.data.FlickrStore;

});
<|endoftext|>


<commit_before>class BaseCommand {
  constructor(bot, type) {
    if (this.constructor === BaseCommand)
      throw new Error('Cannot instantiate abstract BaseCommand.')

    this.bot = bot

    this.aliases = []
    this.id = this.name
    this.type = type

    this.dm = true
    this.maxMessage = 'The content of this command exceeded the maximum length of 2k characters.'
    this.ownerOnly = false
    this.permissions = null
    this.privateGuilds = null
  }

  get name() {
    throw new Error('Name must be overridden.')
  }

  get help() {
    return `No Help Message Currently Created for \`${this.name}\`.`
  }

  async execute(message, content, options = {}) {
    if (!message || !content) {
      return
    } else {
      this.increaseUsage()
      this.bot.log.command(message, this.name)

      if ((content instanceof Object && content.content.length > 2000)) {
        content = this.maxMessage
      } else if (content.length > 2000) {
        content = this.maxMessage
      }

      return await this.sendMessage(message.channel, content, options)
    }
  }

  sendMessage(channel, content, options = {}) {
    return new Promise(resolve => {
      channel.createMessage(content, options.upload ? options.upload : undefined).then(msg => {
        if (options.edit) {
          msg.edit(options.edit(msg))
        }

        resolve(msg)
      }).catch(err => this.bot.log.warn(`${this.name} - Error Sending Message: ${err}`))
    })
  }

  increaseUsage() {
    if (this.bot.commandUsage.has(this.name)) {
      const usage = this.bot.commandUsage.get(this.name) + 1

      this.bot.commandUsage.set(this.name, usage)
    } else {
      this.bot.commandUsage.set(this.name, 1)
    }
  }

  awaitMessage(input, output, timeout) {
    return this.bot.messageHandler.awaitMessage(input, output, timeout)
  }

  reactionButton(emojis, add, remove, messageID, timeout) {
    return this.bot.messageHandler.reactionButton(emojis, add, remove, messageID, timeout)
  }

  permissionsAll(message) {
    if (!this.privateGuildCheck(message.channel.guild)) {
      return false
    } else if (!this.permissionsCheck(message)) {
      return false
    } else if (!this.dm && !message.channel.guild) {
      return false
    } else {
      return true
    }
  }

  privateGuildCheck(guild) {
    if (!this.privateGuilds) {
      return true
    } else if (!guild || !this.privateGuilds.includes(guild.id)) {
      return false
    } else {
      return true
    }
  }

  permissionsCheck(message) {
    let hasPermssion = true

    if (this.permissions != null && message.channel.guild) {
      const permissionKeys = Object.keys(this.permissions)
      const userPermissions = message.channel.permissionsOf(message.author.id).json

      for (const key of permissionKeys)
        if (this.permissions[key] !== userPermissions[key]) {
          hasPermssion = false

          break
        }
    }

    return hasPermssion
  }
}

module.exports = BaseCommand<commit_msg>Add check for content in content object<commit_after>class BaseCommand {
  constructor(bot, type) {
    if (this.constructor === BaseCommand)
      throw new Error('Cannot instantiate abstract BaseCommand.')

    this.bot = bot

    this.aliases = []
    this.id = this.name
    this.type = type

    this.dm = true
    this.maxMessage = 'The content of this command exceeded the maximum length of 2k characters.'
    this.ownerOnly = false
    this.permissions = null
    this.privateGuilds = null
  }

  get name() {
    throw new Error('Name must be overridden.')
  }

  get help() {
    return `No Help Message Currently Created for \`${this.name}\`.`
  }

  async execute(message, content, options = {}) {
    if (!message || !content) {
      return
    } else {
      this.increaseUsage()
      this.bot.log.command(message, this.name)

      if ((content instanceof Object && content.content && content.content.length > 2000)) {
        content = this.maxMessage
      } else if (content.length > 2000) {
        content = this.maxMessage
      }

      return await this.sendMessage(message.channel, content, options)
    }
  }

  sendMessage(channel, content, options = {}) {
    return new Promise(resolve => {
      channel.createMessage(content, options.upload ? options.upload : undefined).then(msg => {
        if (options.edit) {
          msg.edit(options.edit(msg))
        }

        resolve(msg)
      }).catch(err => this.bot.log.warn(`${this.name} - Error Sending Message: ${err}`))
    })
  }

  increaseUsage() {
    if (this.bot.commandUsage.has(this.name)) {
      const usage = this.bot.commandUsage.get(this.name) + 1

      this.bot.commandUsage.set(this.name, usage)
    } else {
      this.bot.commandUsage.set(this.name, 1)
    }
  }

  awaitMessage(input, output, timeout) {
    return this.bot.messageHandler.awaitMessage(input, output, timeout)
  }

  reactionButton(emojis, add, remove, messageID, timeout) {
    return this.bot.messageHandler.reactionButton(emojis, add, remove, messageID, timeout)
  }

  permissionsAll(message) {
    if (!this.privateGuildCheck(message.channel.guild)) {
      return false
    } else if (!this.permissionsCheck(message)) {
      return false
    } else if (!this.dm && !message.channel.guild) {
      return false
    } else {
      return true
    }
  }

  privateGuildCheck(guild) {
    if (!this.privateGuilds) {
      return true
    } else if (!guild || !this.privateGuilds.includes(guild.id)) {
      return false
    } else {
      return true
    }
  }

  permissionsCheck(message) {
    let hasPermssion = true

    if (this.permissions != null && message.channel.guild) {
      const permissionKeys = Object.keys(this.permissions)
      const userPermissions = message.channel.permissionsOf(message.author.id).json

      for (const key of permissionKeys)
        if (this.permissions[key] !== userPermissions[key]) {
          hasPermssion = false

          break
        }
    }

    return hasPermssion
  }
}

module.exports = BaseCommand<|endoftext|>


<commit_before>import * as countryCoder from '@ideditor/country-coder';
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { event as d3_event, select as d3_select } from 'd3-selection';

import { t, localizer } from '../core/localizer';
import { svgIcon } from '../svg/icon';
import { uiTooltip } from './tooltip';
import { geoExtent } from '../geo/extent';
import { uiFieldHelp } from './field_help';
import { uiFields } from './fields';
import { uiTagReference } from './tag_reference';
import { utilRebind, utilUniqueDomId } from '../util';

export function uiField(context, presetField, entityIDs, options) {
    options = Object.assign({
        show: true,
        wrap: true,
        remove: true,
        revert: true,
        info: true
    }, options);

    var dispatch = d3_dispatch('change', 'revert');
    var field = Object.assign({}, presetField);   // shallow copy
    field.domId = utilUniqueDomId('form-field-' + field.safeid);
    var _show = options.show;
    var _state = '';
    var _tags = {};

    var _locked = false;
    var _lockedTip = uiTooltip()
        .title(t('inspector.lock.suggestion', { label: field.label }))
        .placement('bottom');

    field.keys = field.keys || [field.key];

    // only create the fields that are actually being shown
    if (_show && !field.impl) {
        createField();
    }

    // Creates the field.. This is done lazily,
    // once we know that the field will be shown.
    function createField() {
        field.impl = uiFields[field.type](field, context)
            .on('change', function(t, onInput) {
                dispatch.call('change', field, t, onInput);
            });

        if (entityIDs) {
            field.entityIDs = entityIDs;
            // if this field cares about the entities, pass them along
            if (field.impl.entityIDs) {
                field.impl.entityIDs(entityIDs);
            }
        }
    }

    function isModified() {
        if (!entityIDs || !entityIDs.length) return false;
        return entityIDs.some(function(entityID) {
            var original = context.graph().base().entities[entityID];
            var latest = context.graph().entity(entityID);
            return field.keys.some(function(key) {
                return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
            });
        });
    }

    function tagsContainFieldKey() {
        return field.keys.some(function(key) {
            if (field.type === 'multiCombo') {
                for (var tagKey in _tags) {
                    if (tagKey.indexOf(key) === 0) {
                        return true;
                    }
                }
                return false;
            }
            return _tags[key] !== undefined;
        });
    }

    function revert(d) {
        d3_event.stopPropagation();
        d3_event.preventDefault();
        if (!entityIDs || _locked) return;

        dispatch.call('revert', d, d.keys);
    }

    function remove(d) {
        d3_event.stopPropagation();
        d3_event.preventDefault();
        if (_locked) return;

        var t = {};
        d.keys.forEach(function(key) {
            t[key] = undefined;
        });

        dispatch.call('change', d, t);
    }

    field.render = function(selection) {
        var container = selection.selectAll('.form-field')
            .data([field]);

        // Enter
        var enter = container.enter()
            .append('div')
            .attr('class', function(d) { return 'form-field form-field-' + d.safeid; })
            .classed('nowrap', !options.wrap);

        if (options.wrap) {
            var labelEnter = enter
                .append('label')
                .attr('class', 'field-label')
                .attr('for', function(d) { return d.domId; });

            var textEnter = labelEnter
                .append('span')
                .attr('class', 'label-text');

            textEnter
                .append('span')
                .attr('class', 'label-textvalue')
                .text(function(d) { return d.label(); });

            textEnter
                .append('span')
                .attr('class', 'label-textannotation');

            if (options.remove) {
                labelEnter
                    .append('button')
                    .attr('class', 'remove-icon')
                    .attr('title', t('icons.remove'))
                    .attr('tabindex', -1)
                    .call(svgIcon('#iD-operation-delete'));
            }

            if (options.revert) {
                labelEnter
                    .append('button')
                    .attr('class', 'modified-icon')
                    .attr('title', t('icons.undo'))
                    .attr('tabindex', -1)
                    .call(svgIcon((localizer.textDirection() === 'rtl') ? '#iD-icon-redo' : '#iD-icon-undo'));
            }
        }

        // Update
        container = container
            .merge(enter);

        container.select('.field-label > .remove-icon')  // propagate bound data
            .on('click', remove);

        container.select('.field-label > .modified-icon')  // propagate bound data
            .on('click', revert);

        container
            .each(function(d) {
                var selection = d3_select(this);

                if (!d.impl) {
                    createField();
                }

                var reference, help;

                // instantiate field help
                if (options.wrap && field.type === 'restrictions') {
                    help = uiFieldHelp(context, 'restrictions');
                }

                // instantiate tag reference
                if (options.wrap && options.info) {
                    var referenceKey = d.key;
                    if (d.type === 'multiCombo') {   // lookup key without the trailing ':'
                        referenceKey = referenceKey.replace(/:$/, '');
                    }

                    reference = uiTagReference(d.reference || { key: referenceKey }, context);
                    if (_state === 'hover') {
                        reference.showing(false);
                    }
                }

                selection
                    .call(d.impl);

                // add field help components
                if (help) {
                    selection
                        .call(help.body)
                        .select('.field-label')
                        .call(help.button);
                }

                // add tag reference components
                if (reference) {
                    selection
                        .call(reference.body)
                        .select('.field-label')
                        .call(reference.button);
                }

                d.impl.tags(_tags);
            });

            container
                .classed('locked', _locked)
                .classed('modified', isModified())
                .classed('present', tagsContainFieldKey());

            // show a tip and lock icon if the field is locked
            var annotation = container.selectAll('.field-label .label-textannotation');
            var icon = annotation.selectAll('.icon')
                .data(_locked ? [0]: []);

            icon.exit()
                .remove();

            icon.enter()
                .append('svg')
                .attr('class', 'icon')
                .append('use')
                .attr('xlink:href', '#fas-lock');

            container.call(_locked ? _lockedTip : _lockedTip.destroy);
    };

    field.state = function(val) {
        if (!arguments.length) return _state;
        _state = val;
        return field;
    };

    field.tags = function(val) {
        if (!arguments.length) return _tags;
        _tags = val;

        if (tagsContainFieldKey() && !_show) {
            // always show a field if it has a value to display
            _show = true;
            if (!field.impl) {
                createField();
            }
        }

        return field;
    };

    field.locked = function(val) {
        if (!arguments.length) return _locked;
        _locked = val;
        return field;
    };

    field.show = function() {
        _show = true;
        if (!field.impl) {
            createField();
        }
        if (field.default && field.key && _tags[field.key] !== field.default) {
            var t = {};
            t[field.key] = field.default;
            dispatch.call('change', this, t);
        }
    };

    // A shown field has a visible UI, a non-shown field is in the 'Add field' dropdown
    field.isShown = function() {
        return _show;
    };

    // An allowed field can appear in the UI or in the 'Add field' dropdown.
    // A non-allowed field is hidden from the user altogether
    field.isAllowed = function() {

        if (entityIDs &&
            entityIDs.length > 1 &&
            uiFields[field.type].supportsMultiselection === false) return false;

        if (field.geometry && !entityIDs.every(function(entityID) {
            return field.matchGeometry(context.graph().geometry(entityID));
        })) return false;

        if (field.countryCodes || field.notCountryCodes) {
            var extent = combinedEntityExtent();
            if (!extent) return true;

            var center = extent.center();
            var countryCode = countryCoder.iso1A2Code(center);

            if (!countryCode) return false;

            countryCode = countryCode.toLowerCase();

            if (field.countryCodes && field.countryCodes.indexOf(countryCode) === -1) {
                return false;
            }
            if (field.notCountryCodes && field.notCountryCodes.indexOf(countryCode) !== -1) {
                return false;
            }
        }

        var prerequisiteTag = field.prerequisiteTag;

        if (entityIDs &&
            !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
            prerequisiteTag) {
            return entityIDs.some(function(entityID) {
                var entity = context.graph().entity(entityID);
                if (prerequisiteTag.key) {
                    var value = entity.tags[prerequisiteTag.key];
                    if (!value) return false;

                    if (prerequisiteTag.valueNot) {
                        return prerequisiteTag.valueNot !== value;
                    }
                    if (prerequisiteTag.value) {
                        return prerequisiteTag.value === value;
                    }
                } else if (prerequisiteTag.keyNot) {
                    if (entity.tags[prerequisiteTag.keyNot]) return false;
                }
            });
        }

        return true;
    };

    field.focus = function() {
        if (field.impl) {
            field.impl.focus();
        }
    };

    function combinedEntityExtent() {
        return entityIDs && entityIDs.length && entityIDs.reduce(function(extent, entityID) {
            var entity = context.graph().entity(entityID);
            return extent.extend(entity.extent(context.graph()));
        }, geoExtent());
    }

    return utilRebind(field, dispatch, 'on');
}
<commit_msg>Fix issue with prerequisiteTag<commit_after>import * as countryCoder from '@ideditor/country-coder';
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { event as d3_event, select as d3_select } from 'd3-selection';

import { t, localizer } from '../core/localizer';
import { svgIcon } from '../svg/icon';
import { uiTooltip } from './tooltip';
import { geoExtent } from '../geo/extent';
import { uiFieldHelp } from './field_help';
import { uiFields } from './fields';
import { uiTagReference } from './tag_reference';
import { utilRebind, utilUniqueDomId } from '../util';

export function uiField(context, presetField, entityIDs, options) {
    options = Object.assign({
        show: true,
        wrap: true,
        remove: true,
        revert: true,
        info: true
    }, options);

    var dispatch = d3_dispatch('change', 'revert');
    var field = Object.assign({}, presetField);   // shallow copy
    field.domId = utilUniqueDomId('form-field-' + field.safeid);
    var _show = options.show;
    var _state = '';
    var _tags = {};

    var _locked = false;
    var _lockedTip = uiTooltip()
        .title(t('inspector.lock.suggestion', { label: field.label }))
        .placement('bottom');

    field.keys = field.keys || [field.key];

    // only create the fields that are actually being shown
    if (_show && !field.impl) {
        createField();
    }

    // Creates the field.. This is done lazily,
    // once we know that the field will be shown.
    function createField() {
        field.impl = uiFields[field.type](field, context)
            .on('change', function(t, onInput) {
                dispatch.call('change', field, t, onInput);
            });

        if (entityIDs) {
            field.entityIDs = entityIDs;
            // if this field cares about the entities, pass them along
            if (field.impl.entityIDs) {
                field.impl.entityIDs(entityIDs);
            }
        }
    }

    function isModified() {
        if (!entityIDs || !entityIDs.length) return false;
        return entityIDs.some(function(entityID) {
            var original = context.graph().base().entities[entityID];
            var latest = context.graph().entity(entityID);
            return field.keys.some(function(key) {
                return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
            });
        });
    }

    function tagsContainFieldKey() {
        return field.keys.some(function(key) {
            if (field.type === 'multiCombo') {
                for (var tagKey in _tags) {
                    if (tagKey.indexOf(key) === 0) {
                        return true;
                    }
                }
                return false;
            }
            return _tags[key] !== undefined;
        });
    }

    function revert(d) {
        d3_event.stopPropagation();
        d3_event.preventDefault();
        if (!entityIDs || _locked) return;

        dispatch.call('revert', d, d.keys);
    }

    function remove(d) {
        d3_event.stopPropagation();
        d3_event.preventDefault();
        if (_locked) return;

        var t = {};
        d.keys.forEach(function(key) {
            t[key] = undefined;
        });

        dispatch.call('change', d, t);
    }

    field.render = function(selection) {
        var container = selection.selectAll('.form-field')
            .data([field]);

        // Enter
        var enter = container.enter()
            .append('div')
            .attr('class', function(d) { return 'form-field form-field-' + d.safeid; })
            .classed('nowrap', !options.wrap);

        if (options.wrap) {
            var labelEnter = enter
                .append('label')
                .attr('class', 'field-label')
                .attr('for', function(d) { return d.domId; });

            var textEnter = labelEnter
                .append('span')
                .attr('class', 'label-text');

            textEnter
                .append('span')
                .attr('class', 'label-textvalue')
                .text(function(d) { return d.label(); });

            textEnter
                .append('span')
                .attr('class', 'label-textannotation');

            if (options.remove) {
                labelEnter
                    .append('button')
                    .attr('class', 'remove-icon')
                    .attr('title', t('icons.remove'))
                    .attr('tabindex', -1)
                    .call(svgIcon('#iD-operation-delete'));
            }

            if (options.revert) {
                labelEnter
                    .append('button')
                    .attr('class', 'modified-icon')
                    .attr('title', t('icons.undo'))
                    .attr('tabindex', -1)
                    .call(svgIcon((localizer.textDirection() === 'rtl') ? '#iD-icon-redo' : '#iD-icon-undo'));
            }
        }

        // Update
        container = container
            .merge(enter);

        container.select('.field-label > .remove-icon')  // propagate bound data
            .on('click', remove);

        container.select('.field-label > .modified-icon')  // propagate bound data
            .on('click', revert);

        container
            .each(function(d) {
                var selection = d3_select(this);

                if (!d.impl) {
                    createField();
                }

                var reference, help;

                // instantiate field help
                if (options.wrap && field.type === 'restrictions') {
                    help = uiFieldHelp(context, 'restrictions');
                }

                // instantiate tag reference
                if (options.wrap && options.info) {
                    var referenceKey = d.key;
                    if (d.type === 'multiCombo') {   // lookup key without the trailing ':'
                        referenceKey = referenceKey.replace(/:$/, '');
                    }

                    reference = uiTagReference(d.reference || { key: referenceKey }, context);
                    if (_state === 'hover') {
                        reference.showing(false);
                    }
                }

                selection
                    .call(d.impl);

                // add field help components
                if (help) {
                    selection
                        .call(help.body)
                        .select('.field-label')
                        .call(help.button);
                }

                // add tag reference components
                if (reference) {
                    selection
                        .call(reference.body)
                        .select('.field-label')
                        .call(reference.button);
                }

                d.impl.tags(_tags);
            });

            container
                .classed('locked', _locked)
                .classed('modified', isModified())
                .classed('present', tagsContainFieldKey());

            // show a tip and lock icon if the field is locked
            var annotation = container.selectAll('.field-label .label-textannotation');
            var icon = annotation.selectAll('.icon')
                .data(_locked ? [0]: []);

            icon.exit()
                .remove();

            icon.enter()
                .append('svg')
                .attr('class', 'icon')
                .append('use')
                .attr('xlink:href', '#fas-lock');

            container.call(_locked ? _lockedTip : _lockedTip.destroy);
    };

    field.state = function(val) {
        if (!arguments.length) return _state;
        _state = val;
        return field;
    };

    field.tags = function(val) {
        if (!arguments.length) return _tags;
        _tags = val;

        if (tagsContainFieldKey() && !_show) {
            // always show a field if it has a value to display
            _show = true;
            if (!field.impl) {
                createField();
            }
        }

        return field;
    };

    field.locked = function(val) {
        if (!arguments.length) return _locked;
        _locked = val;
        return field;
    };

    field.show = function() {
        _show = true;
        if (!field.impl) {
            createField();
        }
        if (field.default && field.key && _tags[field.key] !== field.default) {
            var t = {};
            t[field.key] = field.default;
            dispatch.call('change', this, t);
        }
    };

    // A shown field has a visible UI, a non-shown field is in the 'Add field' dropdown
    field.isShown = function() {
        return _show;
    };

    // An allowed field can appear in the UI or in the 'Add field' dropdown.
    // A non-allowed field is hidden from the user altogether
    field.isAllowed = function() {

        if (entityIDs &&
            entityIDs.length > 1 &&
            uiFields[field.type].supportsMultiselection === false) return false;

        if (field.geometry && !entityIDs.every(function(entityID) {
            return field.matchGeometry(context.graph().geometry(entityID));
        })) return false;

        if (field.countryCodes || field.notCountryCodes) {
            var extent = combinedEntityExtent();
            if (!extent) return true;

            var center = extent.center();
            var countryCode = countryCoder.iso1A2Code(center);

            if (!countryCode) return false;

            countryCode = countryCode.toLowerCase();

            if (field.countryCodes && field.countryCodes.indexOf(countryCode) === -1) {
                return false;
            }
            if (field.notCountryCodes && field.notCountryCodes.indexOf(countryCode) !== -1) {
                return false;
            }
        }

        var prerequisiteTag = field.prerequisiteTag;

        if (entityIDs &&
            !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
            prerequisiteTag) {

            if (!entityIDs.every(function(entityID) {
                var entity = context.graph().entity(entityID);
                if (prerequisiteTag.key) {
                    var value = entity.tags[prerequisiteTag.key];
                    if (!value) return false;

                    if (prerequisiteTag.valueNot) {
                        return prerequisiteTag.valueNot !== value;
                    }
                    if (prerequisiteTag.value) {
                        return prerequisiteTag.value === value;
                    }
                } else if (prerequisiteTag.keyNot) {
                    if (entity.tags[prerequisiteTag.keyNot]) return false;
                }
                return true;
            })) return false;
        }

        return true;
    };

    field.focus = function() {
        if (field.impl) {
            field.impl.focus();
        }
    };

    function combinedEntityExtent() {
        return entityIDs && entityIDs.length && entityIDs.reduce(function(extent, entityID) {
            var entity = context.graph().entity(entityID);
            return extent.extend(entity.extent(context.graph()));
        }, geoExtent());
    }

    return utilRebind(field, dispatch, 'on');
}
<|endoftext|>


<commit_before>//Copyright (c) 2015 Eric Vallee <eric_vallee2003@yahoo.ca>
//MIT License: https://raw.githubusercontent.com/Magnitus-/ExpressUserLocalBasic/master/License.txt

function GetRoutingVars(Req, Res, Next, Callback)
{
    var RoutingVars = Res.locals.ExpressUser ? Res.locals.ExpressUser : null;
    if(RoutingVars)
    {
        Callback(RoutingVars)
    }
    else
    {
        var Error = new Error();
        Error.Type = "NotValidated";
        Next(Err);
    }
}

var ResponseRoutes = {};

ResponseRoutes['UsersPost'] = function(SendEmail) {
    return(function(Req, Res, Next) {
        GetRoutingVars(Req, Res, Next, function(RoutingVars) {
            if(SendEmail)
            {
                SendEmail(RoutingVars['User'], null, function(Err) {
                    Res.status(201).end();
                });
            }
            else
            {
                Res.status(201).end();
            }
        });
    });
}

ResponseRoutes['UserPatch'] = function(SendEmail) {
    return(function(Req, Res, Next) {
        GetRoutingVars(Req, Res, Next, function(RoutingVars) {
            if(SendEmail)
            {
                SendEmail(RoutingVars['User'], RoutingVars['Update'], function(Err) {
                    Res.status(204).end();
                });
            }
            else
            {
                Res.status(204).end();
            }
        });
    });
}

ResponseRoutes['UserDelete'] = function(Req, Res, Next) {
    GetRoutingVars(Req, Res, Next, function(RoutingVars) {
        Res.status(204).end();
    });
}

ResponseRoutes['UserGet'] = function(GetSerializer) {
    return(function(Req, Res, Next) {
        GetSerializer(Req, Res, Next);
    });
}

ResponseRoutes['UsersCountGet'] = function(CountSerializer) {
    return(function(Req, Res, Next) {
        CountSerializer(Req, Res, Next);
    });
}

ResponseRoutes['UserMembershipsPut'] = function(Req, Res, Next) {
    Res.status(204).end();
}

ResponseRoutes['UserMembershipsDelete'] = function(Req, Res, Next) {
    Res.status(204).end();
}

ResponseRoutes['SessionUserPut'] = function(Req, Res, Next) {
    Res.status(204).end();
}

ResponseRoutes['SessionUserDelete'] = function(Req, Res, Next) {
    Res.status(204).end();
}

function ReturnStatus(Code)
{
    if(Code >= 400)
    {
        return(function(Err, Req, Res, Next) {Res.status(Code).end();});
    }
    else
    {
        return(function(Req, Res, Next) {Res.status(Code).end();});
    }
}

ResponseRoutes['MembershipInsertionErr'] = function(Err, Req, Res, Next) {
    var ReturnStatus404 = ReturnStatus(404);
    if(Err.Source && Err.Type && Err.Source === 'ExpressUser' && Err.Type === 'NoInsertion')
    {
        ReturnStatus404(Err, Req, Res, Next);
    }
    else
    {
        Next(Err);
    }
}

ResponseRoutes['GlobalErr'] = function() {
    var Handler = {};
    Handler['ExpressAccessControl'] = ReturnStatus(401);
    Handler['ExpressUserLocal'] = {};
    Handler['ExpressUserLocal']['BadBody']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['BadField']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['NoAuth']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['NoField']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['NoID']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['PrivateField']  = ReturnStatus(401);
    Handler['ExpressUserLocal']['NoAuto']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['InsecureConnection']  = ReturnStatus(400);
    Handler['ExpressUser'] = {};
    Handler['ExpressUser']['NotValidated'] = ReturnStatus(404);
    Handler['UserStore'] = {};
    Handler['ExpressUser']['StoreConstraint'] = ReturnStatus(409);
    Handler['ExpressUser']['NoInsertion'] = ReturnStatus(400);
    Handler['ExpressUser']['NoUpdate'] = ReturnStatus(404);
    Handler['ExpressUser']['NoDelete'] = ReturnStatus(404);
    Handler['ExpressUser']['NoUser'] = ReturnStatus(404);
    Handler['ExpressUser']['NoSessionUser'] = ReturnStatus(404);

    return(function(Err, Req, Res, Next) {
        if(Err.Type && Err.Source && Handler[Err.Source] !== undefined)
        {
            if(typeof(Handler[Err.Source]) === 'function')
            {
                Handler[Err.Source](Err, Req, Res, Next);
            }
            else if(Handler[Err.Source][Err.Type] !== undefined)
            {
                Handler[Err.Source][Err.Type](Err, Req, Res, Next);
            }
            else
            {
                Next(Err);
            }
        }
        else
        {
            Next(Err);
        }
    });
}

module.exports = function(Options) {
    var Roles = Options && Options.Roles ? Options.Roles : {'Edit': ['Admin'], 'Delete': ['Admin'], 'Get': ['Admin']};
    var SendEmail = Options && Options.SendEmail ? Options.SendEmail : null;
    var GetSerializer = Options && Options.GetSerializer ? Options.GetSerializer : function(Req, Res, Next) {
        GetRoutingVars(Req, Res, Next, function(RoutingVars) {
            var User = RoutingVars.Result;
            if(RoutingVars.Hide)
            {
                RoutingVars.Hide.forEach(function(Field, Index, List) {
                    delete User[Field];
                });
            }
            Res.status(200).json(User);
        });
    };
    var CountSerializer = Options && Options.CountSerializer ? Options.CountSerializer : function(Req, Res, Next) {
        GetRoutingVars(Req, Res, Next, function(RoutingVars) {
            var Count = RoutingVars.Result;
            Res.status(200).json({'Count': Count});
        });
    };

    return function(Router) {
        Router.post('/Users', ResponseRoutes.UsersPost(SendEmail));

        if(Roles&&Roles.Edit)
        {
            Router.patch('/User/:Field/:ID', ResponseRoutes.UserPatch());
            Router.put('/User/:Field/:ID/Memberships/:Membership', ResponseRoutes.UserMembershipsPut);
        }
        Router.patch('/User/Self', ResponseRoutes.UserPatch());
        Router.post('/User/:Field/:ID/Recovery/:SetField', ResponseRoutes.UserPatch(SendEmail));
        Router.put('/User/Self/Memberships/:Membership', ResponseRoutes.UserMembershipsPut);

        if(Roles&&Roles.Delete)
        {
            Router.delete('/User/:Field/:ID', ResponseRoutes.UserDelete);
            Router.delete('/User/:Field/:ID/Memberships/:Membership', ResponseRoutes.UserMembershipsDelete);
        }
        Router.delete('/User/Self', ResponseRoutes.UserDelete);
        Router.delete('/User/Self/Memberships/:Membership', ResponseRoutes.UserMembershipsDelete);

        if(Roles&&Roles.Get)
        {
            Router.get('/User/:Field/:ID', ResponseRoutes.UserGet(GetSerializer));
        }
        Router.get('/User/Self', ResponseRoutes.UserGet(GetSerializer));

        Router.get('/Users/:Field/:ID/Count', ResponseRoutes.UsersCountGet(CountSerializer));

        Router.put('/Session/Self/User', ResponseRoutes.SessionUserPut);

        Router.delete('/Session/Self/User', ResponseRoutes.SessionUserDelete);

        Router.use('/', ReturnStatus(204));
        Router.use('/User/Self/Memberships/Validated', ResponseRoutes.MembershipInsertionErr);
        Router.use('/User/:Field/:ID/Memberships/:Membership', ResponseRoutes.MembershipInsertionErr);
        Router.use('/', ResponseRoutes.GlobalErr());
    };
};

<commit_msg>More refactoring.<commit_after>//Copyright (c) 2015 Eric Vallee <eric_vallee2003@yahoo.ca>
//MIT License: https://raw.githubusercontent.com/Magnitus-/ExpressUserLocalBasic/master/License.txt

function GetRoutingVars(Req, Res, Next, Callback)
{
    var RoutingVars = Res.locals.ExpressUser ? Res.locals.ExpressUser : null;
    if(RoutingVars)
    {
        Callback(RoutingVars)
    }
    else
    {
        var Error = new Error();
        Error.Type = "NotValidated";
        Next(Err);
    }
}

var ResponseRoutes = {};

ResponseRoutes['UsersPost'] = function(SendEmail) {
    return(function(Req, Res, Next) {
        GetRoutingVars(Req, Res, Next, function(RoutingVars) {
            if(SendEmail)
            {
                SendEmail(RoutingVars['User'], null, function(Err) {
                    Res.status(201).end();
                });
            }
            else
            {
                Res.status(201).end();
            }
        });
    });
}

ResponseRoutes['UserPatch'] = function(SendEmail) {
    return(function(Req, Res, Next) {
        GetRoutingVars(Req, Res, Next, function(RoutingVars) {
            if(SendEmail)
            {
                SendEmail(RoutingVars['User'], RoutingVars['Update'], function(Err) {
                    Res.status(204).end();
                });
            }
            else
            {
                Res.status(204).end();
            }
        });
    });
}

ResponseRoutes['UserGet'] = function(GetSerializer) {
    return(function(Req, Res, Next) {
        GetSerializer(Req, Res, Next);
    });
}

ResponseRoutes['UsersCountGet'] = function(CountSerializer) {
    return(function(Req, Res, Next) {
        CountSerializer(Req, Res, Next);
    });
}

function ReturnStatus(Code)
{
    if(Code >= 400)
    {
        return(function(Err, Req, Res, Next) {Res.status(Code).end();});
    }
    else
    {
        return(function(Req, Res, Next) {Res.status(Code).end();});
    }
}

ResponseRoutes['MembershipInsertionErr'] = function(Err, Req, Res, Next) {
    var ReturnStatus404 = ReturnStatus(404);
    if(Err.Source && Err.Type && Err.Source === 'ExpressUser' && Err.Type === 'NoInsertion')
    {
        ReturnStatus404(Err, Req, Res, Next);
    }
    else
    {
        Next(Err);
    }
}

ResponseRoutes['GlobalErr'] = function() {
    var Handler = {};
    Handler['ExpressAccessControl'] = ReturnStatus(401);
    Handler['ExpressUserLocal'] = {};
    Handler['ExpressUserLocal']['BadBody']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['BadField']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['NoAuth']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['NoField']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['NoID']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['PrivateField']  = ReturnStatus(401);
    Handler['ExpressUserLocal']['NoAuto']  = ReturnStatus(400);
    Handler['ExpressUserLocal']['InsecureConnection']  = ReturnStatus(400);
    Handler['ExpressUser'] = {};
    Handler['ExpressUser']['NotValidated'] = ReturnStatus(404);
    Handler['UserStore'] = {};
    Handler['ExpressUser']['StoreConstraint'] = ReturnStatus(409);
    Handler['ExpressUser']['NoInsertion'] = ReturnStatus(400);
    Handler['ExpressUser']['NoUpdate'] = ReturnStatus(404);
    Handler['ExpressUser']['NoDelete'] = ReturnStatus(404);
    Handler['ExpressUser']['NoUser'] = ReturnStatus(404);
    Handler['ExpressUser']['NoSessionUser'] = ReturnStatus(404);

    return(function(Err, Req, Res, Next) {
        if(Err.Type && Err.Source && Handler[Err.Source] !== undefined)
        {
            if(typeof(Handler[Err.Source]) === 'function')
            {
                Handler[Err.Source](Err, Req, Res, Next);
            }
            else if(Handler[Err.Source][Err.Type] !== undefined)
            {
                Handler[Err.Source][Err.Type](Err, Req, Res, Next);
            }
            else
            {
                Next(Err);
            }
        }
        else
        {
            Next(Err);
        }
    });
}

module.exports = function(Options) {
    var Roles = Options && Options.Roles ? Options.Roles : {'Edit': ['Admin'], 'Delete': ['Admin'], 'Get': ['Admin']};
    var SendEmail = Options && Options.SendEmail ? Options.SendEmail : null;
    var GetSerializer = Options && Options.GetSerializer ? Options.GetSerializer : function(Req, Res, Next) {
        GetRoutingVars(Req, Res, Next, function(RoutingVars) {
            var User = RoutingVars.Result;
            if(RoutingVars.Hide)
            {
                RoutingVars.Hide.forEach(function(Field, Index, List) {
                    delete User[Field];
                });
            }
            Res.status(200).json(User);
        });
    };
    var CountSerializer = Options && Options.CountSerializer ? Options.CountSerializer : function(Req, Res, Next) {
        GetRoutingVars(Req, Res, Next, function(RoutingVars) {
            var Count = RoutingVars.Result;
            Res.status(200).json({'Count': Count});
        });
    };

    return function(Router) {
        Router.post('/Users', ResponseRoutes.UsersPost(SendEmail));

        if(Roles&&Roles.Get)
        {
            Router.get('/User/:Field/:ID', ResponseRoutes.UserGet(GetSerializer));
        }
        Router.get('/User/Self', ResponseRoutes.UserGet(GetSerializer));
        Router.get('/Users/:Field/:ID/Count', ResponseRoutes.UsersCountGet(CountSerializer));

        if(Roles&&Roles.Delete)
        {
            Router.delete('/User/:Field/:ID', ReturnStatus(204));
            Router.delete('/User/:Field/:ID/Memberships/:Membership', ReturnStatus(204));
        }
        Router.delete('/User/Self', ReturnStatus(204));
        Router.delete('/User/Self/Memberships/:Membership', ReturnStatus(204));

        Router.put('/Session/Self/User', ReturnStatus(204));
        Router.delete('/Session/Self/User', ReturnStatus(204));

        if(Roles&&Roles.Edit)
        {
            Router.patch('/User/:Field/:ID', ResponseRoutes.UserPatch());
            Router.put('/User/:Field/:ID/Memberships/:Membership', ReturnStatus(201));
        }
        Router.patch('/User/Self', ResponseRoutes.UserPatch());
        Router.post('/User/:Field/:ID/Recovery/:SetField', ResponseRoutes.UserPatch(SendEmail));
        Router.put('/User/Self/Memberships/:Membership', ReturnStatus(201));

        Router.use('/User/Self/Memberships/Validated', ResponseRoutes.MembershipInsertionErr);
        Router.use('/User/:Field/:ID/Memberships/:Membership', ResponseRoutes.MembershipInsertionErr);
        Router.use('/', ResponseRoutes.GlobalErr());
    };
};

<|endoftext|>


<commit_before>import Moment from "moment";
import "moment-range";

export var YEAR = (new Moment()).year();

export function Timestamp( date = new Date() ) {
    return Moment(date).format("x");
}

export function TimestampInt( date = new Date() ) {
    return Number.parseInt( Timestamp(date) );
}

// ISO8601
export function TimestampISO( date = new Date() ) {
    return Moment(date).toISOString();
}

export function DateInputFormat( date = new Date() ) {
    return Moment(date).format("YYYY-MM-DD");
}

export function FriendlyDate( date = new Date() ) {
    var moment = Moment(date);
    var momentNow = Moment();
    if(momentNow.diff(moment, "minutes") <= 2) {
        return "just now";
    } else if(moment.isSame(momentNow, "day")) {
        return moment.from(momentNow);

    } else if (moment.isSame(momentNow, "week")) {
        return moment.format("ddd");

    } else if (moment.isSame(momentNow, "year")) {
        return moment.format("MMM D");
    } else {
        return moment.format("MMM D, YYYY");
    }
}

export function RangeForCalendarYear( year = YEAR ) {
    var start = new Moment({ year, month: 1, day: 1 });
    var end = start.clone().endOf("year");

    return Moment.range( start, end );
}

export function Range12MonthsPrevious( startDate = new Date() ) {
    var end = new Moment(startDate);
    var start = end.clone().subtract(11, "month");

    return Moment.range( start, end );
}

export function RangeXMonthsPrevious( startDate = new Date(), months = 1 ) {
    var end = new Moment(startDate);
    var start = end.clone().subtract(months, "month");

    return Moment.range( start, end );
}<commit_msg>Converted moment shortcuts back to older es syntax<commit_after>var Moment = require("moment");
require("moment-range");

var YEAR = (new Moment()).year();
module.exports.YEAR = YEAR;

function Timestamp( date ) {
    if(!date) {
        date = new Date();
    }
    return Moment(date).format("x");
}
module.exports.Timestamp = Timestamp;

function TimestampInt( date ) {
    if(!date) {
        date = new Date();
    }
    return Number.parseInt( Timestamp(date) );
}
module.exports.TimestampInt = TimestampInt;

// ISO8601
function TimestampISO( date ) {
    if(!date) {
        date = new Date();
    }
    return Moment(date).toISOString();
}
module.exports.TimestampISO = TimestampISO;

function DateInputFormat( date ) {
    if(!date) {
        date = new Date();
    }
    return Moment(date).format("YYYY-MM-DD");
}
module.exports.DateInputFormat = DateInputFormat;

function FriendlyDate( date ) {
    if(!date) {
        date = new Date();
    }
    var moment = Moment(date);
    var momentNow = Moment();
    if(momentNow.diff(moment, "minutes") <= 2) {
        return "just now";
    } else if(moment.isSame(momentNow, "day")) {
        return moment.from(momentNow);

    } else if (moment.isSame(momentNow, "week")) {
        return moment.format("ddd");

    } else if (moment.isSame(momentNow, "year")) {
        return moment.format("MMM D");
    } else {
        return moment.format("MMM D, YYYY");
    }
}
module.exports.FriendlyDate = FriendlyDate;

function RangeForCalendarYear( year ) {
    if(!year) {
        year = YEAR;
    }
    var start = new Moment({ year: year, month: 1, day: 1 });
    var end = start.clone().endOf("year");

    return Moment.range( start, end );
}
module.exports.RangeForCalendarYear = RangeForCalendarYear;

function Range12MonthsPrevious( startDate ) {
    if(!startDate) {
        startDate = new Date();
    }
    var end = new Moment(startDate);
    var start = end.clone().subtract(11, "month");

    return Moment.range( start, end );
}
module.exports.Range12MonthsPrevious = Range12MonthsPrevious;

function RangeXMonthsPrevious( startDate, months ) {
    if(!startDate) {
        startDate = new Date();
    }
    if(!months) {
        months = 1;
    }
    var end = new Moment(startDate);
    var start = end.clone().subtract(months, "month");

    return Moment.range( start, end );
}
module.exports.RangeXMonthsPrevious = RangeXMonthsPrevious;

<|endoftext|>


<commit_before>import React from 'react';
import FilterPaneSearch from '../FilterPaneSearch';
import Pane from '../Pane';
import FilterControlGroup from '../FilterControlGroup';
import Checkbox from '../Checkbox';
import Button from '../Button';
import RadioButton from '../RadioButton';
import Select from '../Select'
import TextField from '../TextField'

class FilterPane extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      patronFilter: true,
      employeeFilter: false,
      searchTerm: ''
    };
  }

  updateFilters(e) {
    let stateObj = {};
    stateObj[e.target.id] = !this.state[e.target.id];
    this.setState(stateObj);
  }

  updateSearchTerm(e) {
    let term = e.target.value;
    this.setState({ searchTerm: term });
  }

  render() {
    return (
      <Pane
        defaultWidth="16%"
        header={
          <FilterPaneSearch
            searchFieldId={this.props.searchFieldId}
            clearSearchId={this.props.clearSearchId}
          />
        }
      >
        <FilterControlGroup label="Filters">
          <Checkbox id="patronFilter" label="Patrons" noSpacer hover fullWidth />
          <Checkbox id="employeeFilter" label="Employees" noSpacer hover fullWidth />
          <Checkbox id="uncontrolledFilter" label="Uncontrolled" noSpacer hover fullWidth />
        </FilterControlGroup>
        <FilterControlGroup label="Actions">
          <Button fullWidth>Add User</Button>
        </FilterControlGroup>
      </Pane>
    );
  }
}

export default FilterPane;
<commit_msg>semicolon cleanup. see STRPCOMP-21<commit_after>import React from 'react';
import FilterPaneSearch from '../FilterPaneSearch';
import Pane from '../Pane';
import FilterControlGroup from '../FilterControlGroup';
import Checkbox from '../Checkbox';
import Button from '../Button';
import RadioButton from '../RadioButton';
import Select from '../Select';
import TextField from '../TextField';

class FilterPane extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      patronFilter: true,
      employeeFilter: false,
      searchTerm: ''
    };
  }

  updateFilters(e) {
    let stateObj = {};
    stateObj[e.target.id] = !this.state[e.target.id];
    this.setState(stateObj);
  }

  updateSearchTerm(e) {
    let term = e.target.value;
    this.setState({ searchTerm: term });
  }

  render() {
    return (
      <Pane
        defaultWidth="16%"
        header={
          <FilterPaneSearch
            searchFieldId={this.props.searchFieldId}
            clearSearchId={this.props.clearSearchId}
          />
        }
      >
        <FilterControlGroup label="Filters">
          <Checkbox id="patronFilter" label="Patrons" noSpacer hover fullWidth />
          <Checkbox id="employeeFilter" label="Employees" noSpacer hover fullWidth />
          <Checkbox id="uncontrolledFilter" label="Uncontrolled" noSpacer hover fullWidth />
        </FilterControlGroup>
        <FilterControlGroup label="Actions">
          <Button fullWidth>Add User</Button>
        </FilterControlGroup>
      </Pane>
    );
  }
}

export default FilterPane;
<|endoftext|>