Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

partial implementation of luxon #932

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions api/controllers/AdminController.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import moment from 'moment-timezone'
import { DateTime } from 'luxon'
import { merge, transform, sortBy } from 'lodash'

// TODO: this is old and broken
var rawMetricsQuery = startTime => Promise.props({
const rawMetricsQuery = startTime => Promise.props({
community: Community.query(q => {
q.select(['id', 'name', 'created_at', 'avatar_url'])
}).query(),
Expand Down Expand Up @@ -31,39 +31,39 @@ var rawMetricsQuery = startTime => Promise.props({
module.exports = {
loginAsUser: function (req, res) {
return User.find(req.param('userId'))
.then(user => UserSession.login(req, user, 'admin'))
.then(() => res.redirect('/app'))
.then(user => UserSession.login(req, user, 'admin'))
.then(() => res.redirect('/app'))
},

rawMetrics: function (req, res) {
const startTime = moment().subtract(3, 'months').toDate()
const startTime = DateTime.now().minus({ months: 3 }).toJSDate()
return rawMetricsQuery(startTime)
.then(props => {
let result = props.community.reduce((acc, c) => {
acc[c.id] = merge(c, {events: []})
return acc
}, {})
.then(props => {
let result = props.community.reduce((acc, c) => {
acc[c.id] = merge(c, { events: [] })
return acc
}, {})

result.none = {id: 'none', name: 'No community', events: []}
result.none = { id: 'none', name: 'No community', events: [] }

;['user', 'post', 'comment'].forEach(name => {
props[name].forEach(item => {
const key = item.community_id || 'none'
result[key].events.push({
time: Date.parse(item.created_at),
user_id: item.user_id || item.id,
name
;['user', 'post', 'comment'].forEach(name => {
props[name].forEach(item => {
const key = item.community_id || 'none'
result[key].events.push({
time: Date.parse(item.created_at),
user_id: item.user_id || item.id,
name
})
})
})
})

result = transform(result, (acc, c, k) => {
if (c.events.length === 0) return
c.events = sortBy(c.events, 'time')
acc[k] = c
}, {})
result = transform(result, (acc, c, k) => {
if (c.events.length === 0) return
c.events = sortBy(c.events, 'time')
acc[k] = c
}, {})

res.ok(result)
})
res.ok(result)
})
}
}
20 changes: 11 additions & 9 deletions api/models/event/mixin.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { uniq, difference } from 'lodash/fp'
import moment from 'moment-timezone'
import { DateTime } from 'luxon'

export default {
isEvent () {
Expand All @@ -8,7 +8,7 @@ export default {

eventInvitees: function () {
return this.belongsToMany(User).through(EventInvitation, 'event_id', 'user_id')
.withPivot('response')
.withPivot('response')
},

eventInvitations: function () {
Expand Down Expand Up @@ -49,24 +49,26 @@ export default {

prettyEventDates: function (startTime, endTime) {
if (!startTime && !endTime) return null
const start = moment(startTime)
const end = moment(endTime)
const dateNoYearWithTime = { weekday: 'short', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric' }
const dateNoYearNoMonthWithTime = { weekday: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric' }
const start = startTime instanceof Date ? DateTime.fromJSDate(startTime) : typeof startTime === 'number' ? DateTime.fromMillis(startTime) : DateTime.fromISO(startTime)
const end = endTime instanceof Date ? DateTime.fromJSDate(endTime) : typeof endTime === 'number' ? DateTime.fromMillis(endTime) : DateTime.fromISO(endTime)

const from = start.format('ddd, MMM D [at] h:mmA')
const from = start.toLocaleString(dateNoYearWithTime)

let to = ''

if (endTime) {
if (end.month() !== start.month()) {
to = end.format(' - ddd, MMM D [at] h:mmA')
to = ` - ${end.toLocaleString(dateNoYearWithTime)}`
} else if (end.day() !== start.day()) {
to = end.format(' - ddd D [at] h:mmA')
to = ` - ${end.toLocaleString(dateNoYearNoMonthWithTime)}`
} else {
to = end.format(' - h:mmA')
to = ` - ${end.toLocaleString(DateTime.TIME_WITH_SECONDS)}`
}
}

return from + to + " UTC"
return from + to + ' UTC'
},

createInviteNotifications: async function (userId, inviteeIds) {
Expand Down
27 changes: 14 additions & 13 deletions api/services/RequestValidation.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
var moment = require('moment-timezone');
const { DateTime } = require('luxon')

module.exports = {

requireTimeRange: function(req, res) {
var valid = true;
requireTimeRange: function (req, res) {
let valid = true

_.each(['start_time', 'end_time'], function (attr) {
var value = req.param(attr);
const value = req.param(attr)

if (!value) {
res.badRequest(attr + ' is missing');
valid = false;
return false; // break from each
res.badRequest(attr + ' is missing')
valid = false
return false // break from each
}
const time = value instanceof Date ? DateTime.fromJSDate(value) : typeof value === 'number' ? DateTime.fromMillis(value) : DateTime.fromISO(value)

if (!moment(value).isValid()) {
res.badRequest(attr + ' is not a valid ISO8601 date string');
valid = false;
return false; // break from each
if (!time.isValid) {
res.badRequest(attr + ' is not a valid ISO8601 date string')
valid = false
return false // break from each
}
});
})

return valid;
return valid
}

}
32 changes: 15 additions & 17 deletions api/services/Search/util.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GraphQLYogaError } from '@graphql-yoga/node'
import { curry, includes, isEmpty, values } from 'lodash'
import moment from 'moment-timezone'
import { DateTime } from 'luxon'
import addTermToQueryBuilder from './addTermToQueryBuilder'

export const filterAndSortPosts = curry((opts, q) => {
Expand Down Expand Up @@ -32,7 +32,7 @@ export const filterAndSortPosts = curry((opts, q) => {
reactions: 'posts.num_people_reacts',
start_time: 'posts.start_time',
updated: 'posts.updated_at',
votes: 'posts.num_people_reacts', // Need to remove once Mobile has been ported to reactions
votes: 'posts.num_people_reacts' // Need to remove once Mobile has been ported to reactions
}

const sort = sortColumns[sortBy] || values(sortColumns).find(v => v === 'posts.' + sortBy || v === sortBy)
Expand All @@ -51,41 +51,41 @@ export const filterAndSortPosts = curry((opts, q) => {
const { CHAT, DISCUSSION, REQUEST, OFFER, PROJECT, EVENT, RESOURCE } = Post.Type

if (isAnnouncement) {
q.where('announcement', true).andWhere('posts.created_at', '>=', moment().subtract(1, 'month').toDate())
q.where('announcement', true).andWhere('posts.created_at', '>=', DateTime.now().minus({ months: 1 }).toJSDate())
}

if (isFulfilled === true) {
q.where(q2 => {
q2.whereNotNull('posts.fulfilled_at')
.orWhere('posts.end_time', '<', moment().toDate())
.orWhere('posts.end_time', '<', DateTime.now().toJSDate())
})
} else if (isFulfilled === false) {
q.whereNull('posts.fulfilled_at')
.andWhere(q2 => {
q2.whereNull('posts.end_time')
.orWhere('posts.end_time', '>=', moment().toDate())
})
.andWhere(q2 => {
q2.whereNull('posts.end_time')
.orWhere('posts.end_time', '>=', DateTime.now().toJSDate())
})
}

if (activePostsOnly) {
q.whereNull('posts.fulfilled_at')
.andWhere(q2 => {
q2.whereNull('posts.end_time')
.orWhere('posts.end_time', '>=', moment().toDate())
})
.andWhere(q2 => {
q2.whereNull('posts.end_time')
.orWhere('posts.end_time', '>=', DateTime.now().toJSDate())
})
}

if (afterTime) {
q.where(q2 =>
q2.where('posts.start_time', '>=', afterTime)
.orWhere('posts.end_time', '>=', afterTime)
.orWhere('posts.end_time', '>=', afterTime)
)
}

if (beforeTime) {
q.where(q2 =>
q2.where('posts.start_time', '<', beforeTime)
.andWhere('posts.end_time', '<', beforeTime)
.andWhere('posts.end_time', '<', beforeTime)
)
}

Expand All @@ -111,7 +111,7 @@ export const filterAndSortPosts = curry((opts, q) => {
if (!includes(values(Post.Type), type)) {
throw new GraphQLYogaError(`unknown post type: "${type}"`)
}
q.where({'posts.type': type})
q.where({ 'posts.type': type })
}

if (!isEmpty(search)) {
Expand Down Expand Up @@ -144,7 +144,6 @@ export const filterAndSortPosts = curry((opts, q) => {
} else if (sort) {
q.orderBy(sort, order || (sortBy === 'order' ? 'asc' : 'desc'))
}

})

export const filterAndSortUsers = curry(({ autocomplete, boundingBox, order, search, sortBy }, q) => {
Expand Down Expand Up @@ -186,7 +185,6 @@ export const filterAndSortUsers = curry(({ autocomplete, boundingBox, order, sea
})

export const filterAndSortGroups = curry((opts, q) => {

const { search, sortBy = 'name', boundingBox, order } = opts

if (search) {
Expand Down
18 changes: 9 additions & 9 deletions cron.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/* globals Nexudus */
require("@babel/register")
var skiff = require('./lib/skiff') // this must be required first
var moment = require('moment-timezone')
var rollbar = require('./lib/rollbar')
var sails = skiff.sails
var digest2 = require('./lib/group/digest2')
var Promise = require('bluebird')
var { red } = require('chalk')
require('@babel/register')
const skiff = require('./lib/skiff') // this must be required first
const { DateTime } = require('luxon')
const rollbar = require('./lib/rollbar')
const sails = skiff.sails
const digest2 = require('./lib/group/digest2')
const Promise = require('bluebird')
const { red } = require('chalk')
const savedSearches = require('./lib/group/digest2/savedSearches')

const sendAndLogDigests = type =>
Expand Down Expand Up @@ -82,7 +82,7 @@ var runJob = Promise.method(name => {
throw new Error(`Unknown job name: "${name}"`)
}
sails.log.debug(`Running ${name} job`)
const now = moment.tz('America/Los_Angeles')
const now = DateTime.now().setZone('America/Los_Angeles')
return Promise.all(job(now))
})

Expand Down
10 changes: 7 additions & 3 deletions lib/group/digest2/formatData.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import {
curry, every, filter, find, isEmpty, map, pickBy, sortBy
} from 'lodash/fp'
import moment from 'moment-timezone'
import { TextHelpers } from 'hylo-shared'
import { DateTime } from 'luxon'

const isChat = post => post.get('type') === 'chat'
const isRequest = post => post.get('type') === 'request'
Expand All @@ -18,7 +17,12 @@ export const presentAuthor = obj =>

const humanDate = (date) => {
if (!date) return null
return moment(date).format('MMMM D, YYYY @ h:mma')
const formattedDate = date instanceof Date
? DateTime.fromJSDate(date).toLocaleString(DateTime.DATETIME_FULL)
: typeof date === 'number'
? DateTime.fromMillis(date).toLocaleString(DateTime.DATETIME_FULL)
: DateTime.fromISO(date).toLocaleString(DateTime.DATETIME_FULL)
return formattedDate
}

const presentPost = curry((slug, post) => {
Expand Down
31 changes: 19 additions & 12 deletions lib/group/digest2/savedSearches.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { merge, pick, pickBy } from 'lodash/fp'
import moment from 'moment-timezone'
import { DateTime } from 'luxon'
import { pluralize } from '../../util/normalize'
import { presentAuthor } from '../digest2/formatData'
import { sendToUser } from '../digest2'

const humanDate = date => moment(date).format('MMMM D, YYYY')
const humanDate = date => {
const formattedDate = date instanceof Date
? DateTime.fromJSDate(date).toLocaleString(DateTime.DATETIME_FULL)
: typeof date === 'number'
? DateTime.fromMillis(date).toLocaleString(DateTime.DATETIME_FULL)
: DateTime.fromISO(date).toLocaleString(DateTime.DATETIME_FULL)
return formattedDate
}

const presentPost = async (p, context, slug) => {
const post = await Post.where({id: p.id}).fetch()
await post.load(['linkPreview','user'])
const post = await Post.where({ id: p.id }).fetch()
await post.load(['linkPreview', 'user'])
const { linkPreview } = post.relations
return pickBy(x => x, {
id: post.id,
Expand Down Expand Up @@ -58,7 +65,7 @@ const prepareDigestData = async (searchId) => {
const shouldSendData = (data, user, type) => {
const postTypes = ['requests', 'offers', 'events', 'discussions', 'projects', 'resources']
const hasNewPosts = Object.keys(pick(postTypes, data)).some(s => postTypes.includes(s))
const userSettingMatchesType = user.get('settings')['digest_frequency'] === type
const userSettingMatchesType = user.get('settings').digest_frequency === type
return hasNewPosts && userSettingMatchesType
}

Expand All @@ -67,13 +74,13 @@ const sendDigest = async (searchId, type) => {
const { lastPostId, user } = data
if (shouldSendData(data, user, type)) return merge(await sendToUser(user, type, data), { lastPostId })
})
.then(async (sent = {}) => {
const { lastPostId, success } = sent
if (success) {
const search = await SavedSearch.where({ id: searchId }).fetch()
return await search.updateLastPost(searchId, lastPostId)
}
})
.then(async (sent = {}) => {
const { lastPostId, success } = sent
if (success) {
const search = await SavedSearch.where({ id: searchId }).fetch()
return await search.updateLastPost(searchId, lastPostId)
}
})
}

export const sendAllDigests = async (type) => {
Expand Down
Loading